diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsManager.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsManager.kt index 50fd794699..d6be424fc9 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsManager.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsManager.kt @@ -101,6 +101,8 @@ class FunctionCoreToolsManager { return null } + LOG.trace { "Latest Functions tooling release path: $latestReleasePath " } + return latestReleasePath } @@ -121,6 +123,7 @@ class FunctionCoreToolsManager { .map { it.functionsVersion } .toMutableList() versionsManagedByRider.add("v0") + LOG.trace { "Functions tooling managed by Rider: ${versionsManagedByRider.joinToString()}" } val coreToolsDownloadFolder = settings.functionDownloadPath if (coreToolsDownloadFolder.isEmpty()) { @@ -130,7 +133,10 @@ class FunctionCoreToolsManager { val versionsToUpdate = versionsManagedByRider.filter { coreToolsDownloadFolderPath.resolve(it).exists() } - if (versionsToUpdate.isEmpty()) return + if (versionsToUpdate.isEmpty()) { + LOG.trace { "Unable to find any Functions tooling versions to update" } + return + } val toolingReleases = FunctionsToolingFeedService .getInstance() @@ -155,6 +161,8 @@ class FunctionCoreToolsManager { releaseTag: String, coreToolsDownloadFolder: Path ) { + LOG.trace { "Updating Functions tooling. Version: $functionsVersion, release: $releaseTag, folder: $coreToolsDownloadFolder" } + val coreToolsPath = coreToolsDownloadFolder.resolve(functionsVersion).resolve(releaseTag) if (coreToolsPath.exists() && coreToolsPath.resolveFunctionCoreToolsExecutable().exists()) { LOG.trace { "Core tools with tag $releaseTag already exists" } @@ -170,6 +178,8 @@ class FunctionCoreToolsManager { } private fun cleanUpCoreToolsForVersion(functionsVersion: String, coreToolsDownloadFolder: Path) { + LOG.trace { "Cleaning Functions tooling folders. Version: $functionsVersion, download folder: $coreToolsDownloadFolder" } + val coreToolsPathForVersion = coreToolsDownloadFolder.resolve(functionsVersion) val tagFolders = coreToolsPathForVersion.listAllTagFolders() @@ -190,7 +200,7 @@ class FunctionCoreToolsManager { val folderCountToDelete = tagFoldersWithoutEmpty.size - CORE_TOOLING_FOLDERS_COUNT for (tagFolderToDelete in tagFoldersWithoutEmpty.takeLast(folderCountToDelete)) { runCatching { - LOG.trace("Removing core tools folder $tagFolderToDelete") + LOG.trace { "Removing core tools folder $tagFolderToDelete" } tagFolderToDelete.deleteRecursively() }.onFailure { LOG.trace(it) diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsReleaseFeedService.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsReleaseFeedService.kt deleted file mode 100644 index 8e6ec19aa4..0000000000 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/coreTools/FunctionCoreToolsReleaseFeedService.kt +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2018-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the MIT license. - */ - -@file:OptIn(ExperimentalSerializationApi::class) - -package com.microsoft.azure.toolkit.intellij.legacy.function.coreTools - -import com.intellij.openapi.Disposable -import com.intellij.openapi.components.Service -import com.intellij.openapi.components.service -import com.intellij.util.net.ssl.CertificateManager -import io.ktor.client.* -import io.ktor.client.call.* -import io.ktor.client.engine.cio.* -import io.ktor.client.plugins.contentnegotiation.* -import io.ktor.client.request.* -import io.ktor.serialization.kotlinx.json.* -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.Json - -@Service(Service.Level.APP) -class FunctionCoreToolsReleaseFeedService : Disposable { - companion object { - fun getInstance(): FunctionCoreToolsReleaseFeedService = service() - } - - private val client = HttpClient(CIO) { - engine { - https { - trustManager = CertificateManager.getInstance().trustManager - } - } - install(ContentNegotiation) { - json(Json { - explicitNulls = false - ignoreUnknownKeys = true - allowTrailingComma = true - }) - } - } - - suspend fun getReleaseFeed(feedUrl: String): ReleaseFeed { - val response = client.get(feedUrl) - return response.body() - } - - override fun dispose() = client.close() -} - -@Serializable -data class ReleaseFeed( - @SerialName("tags") - val tags: Map, - @SerialName("releases") - val releases: Map -) - -@Serializable -data class Tag( - @SerialName("release") - val release: String?, - @SerialName("releaseQuality") - val releaseQuality: String?, - @SerialName("hidden") - val hidden: Boolean -) - -@Serializable -data class Release( - @SerialName("templates") - val templates: String?, - @SerialName("coreTools") - val coreTools: List -) - -@Serializable -data class ReleaseCoreTool( - @SerialName("OS") - val os: String?, - @SerialName("Architecture") - val architecture: String?, - @SerialName("downloadLink") - val downloadLink: String?, - @SerialName("sha2") - val sha2: String?, - @SerialName("size") - val size: String?, - @SerialName("default") - val default: Boolean -) \ No newline at end of file diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/runner/localRun/FunctionHostDebugLauncher.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/runner/localRun/FunctionHostDebugLauncher.kt index ee05f38f58..45b6752719 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/runner/localRun/FunctionHostDebugLauncher.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/runner/localRun/FunctionHostDebugLauncher.kt @@ -11,6 +11,7 @@ import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.debug import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.diagnostic.trace import com.intellij.openapi.project.Project import com.intellij.openapi.util.io.FileUtil import com.intellij.util.execution.ParametersListUtil @@ -72,6 +73,7 @@ class FunctionHostDebugLauncher(private val project: Project) { dotNetRuntime: DotNetRuntime ): Pair { val temporaryPidFile = withContext(Dispatchers.IO) { createTemporaryPidFile() } + LOG.trace { "Created temporary file ${temporaryPidFile.absolutePath}" } val programParameters = modifyProgramParameters(executable.programParameterString, temporaryPidFile) LOG.debug { "Program parameters: $programParameters" } val environmentVariables = modifyEnvironmentVariables(executable.environmentVariables) @@ -155,6 +157,8 @@ class FunctionHostDebugLauncher(private val project: Project) { LOG.debug("Got functions isolated worker process id from JSON output") LOG.debug { "Functions isolated worker process id: $pidFromJsonOutput" } return pidFromJsonOutput + } else { + LOG.debug("Unable to read process id from JSON file") } delay(500) @@ -166,10 +170,20 @@ class FunctionHostDebugLauncher(private val project: Project) { } private suspend fun readPidFromJsonOutput(pidFile: File): Int? { - if (!pidFile.exists()) return null + if (!pidFile.exists()) { + LOG.trace { "${pidFile.absolutePath} does not exist" } + return null + } val jsonText = withContext(Dispatchers.IO) { pidFile.readText() } - if (jsonText.isEmpty()) return null + if (jsonText.isEmpty()) { + LOG.trace { "${pidFile.absolutePath} is empty" } + return null + } else { + LOG.trace { "Content of ${pidFile.absolutePath}: $jsonText" } + } val content = json.decodeFromString(jsonText) + LOG.trace { "Decoded content of ${pidFile.absolutePath}: $content" } + return content.workerProcessId } diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/runner/localRun/HostJsonPatcher.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/runner/localRun/HostJsonPatcher.kt index 519dcc3955..f41e2f87e6 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/runner/localRun/HostJsonPatcher.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/runner/localRun/HostJsonPatcher.kt @@ -8,6 +8,7 @@ import com.google.gson.* import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.diagnostic.trace import java.nio.file.Path import kotlin.io.path.* @@ -63,7 +64,7 @@ class HostJsonPatcher { .filter { it.isNotBlank() } .sortedBy { it } - LOG.debug("Patching " + hostJsonFile.absolutePathString() + " with function names: ${functions.joinToString(", ")}") + LOG.trace { "Patching ${hostJsonFile.absolutePathString()} with function names: ${functions.joinToString(", ")}" } try { val gson = GsonBuilder().setPrettyPrinting().create() val hostJson = gson.fromJson(hostJsonFile.readText(), JsonElement::class.java).asJsonObject diff --git a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/toolingFeed/FunctionsToolingFeedService.kt b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/toolingFeed/FunctionsToolingFeedService.kt index 314674c6ca..b6827f8f1c 100644 --- a/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/toolingFeed/FunctionsToolingFeedService.kt +++ b/PluginsAndFeatures/azure-toolkit-for-rider/azure-intellij-plugin-appservice-dotnet/src/main/kotlin/com/microsoft/azure/toolkit/intellij/legacy/function/toolingFeed/FunctionsToolingFeedService.kt @@ -78,6 +78,8 @@ class FunctionsToolingFeedService : Disposable { suspend fun downloadAndSaveReleaseFeed() = kotlin.runCatching { if (releaseCache.isNotEmpty()) return@runCatching + LOG.trace("Downloading Functions tooling release feed") + val feed = getReleaseFeed() val releaseTags = feed.tags .toSortedMap() @@ -88,9 +90,10 @@ class FunctionsToolingFeedService : Disposable { val releaseFromTag = fixedReleases[releaseTagName] ?: releaseTag.release ?: continue val release = feed.releases[releaseFromTag] ?: continue val coreToolsRelease = release.findCoreToolsRelease(releaseFilter) ?: continue - LOG.debug("Release for Azure core tools version ${releaseTagName.lowercase()}: ${releaseTag.release}; ${coreToolsRelease.downloadLink}") val releaseKey = releaseTagName.lowercase() + LOG.debug("Release for Azure core tools version ${releaseKey}: ${releaseFromTag}; ${coreToolsRelease.downloadLink}") + releaseCache.putIfAbsent( releaseKey, FunctionsToolingRelease(releaseKey, releaseFromTag, coreToolsRelease.downloadLink ?: "") @@ -156,6 +159,7 @@ class FunctionsToolingFeedService : Disposable { if (!toolingReleasePath.exists()) toolingReleasePath.createDirectories() + LOG.trace { "Extracting from ${tempFile.absolutePath} to $toolingReleasePath" } ZipUtil.extract(tempFile.toPath(), toolingReleasePath, null, true) if (tempFile.exists()) @@ -166,8 +170,8 @@ class FunctionsToolingFeedService : Disposable { return Result.success(toolingReleasePath) } catch (e: Exception) { - toolingReleasePath.deleteRecursively() LOG.warn("Unable to download Function core tools for the runtime version $azureFunctionsVersion") + toolingReleasePath.deleteRecursively() return Result.failure(e) } } @@ -182,35 +186,40 @@ class FunctionsToolingFeedService : Disposable { } private suspend fun getReleaseFeed(): ReleaseFeed { - val feedUrl = getReleaseFeedUrl() + val feedUrl = Registry.get("azure.function_app.core_tools.feed.url").asString() + LOG.trace { "Functions tooling release feed: $feedUrl" } + val response = withContext(Dispatchers.IO) { client.get(feedUrl) } + return response.body() } - private fun getReleaseFeedUrl() = Registry.get("azure.function_app.core_tools.feed.url").asString() - private fun getLatestFunctionsToolingRelease(azureFunctionsVersion: String): FunctionsToolingRelease? { val toolingRelease = releaseCache[azureFunctionsVersion.lowercase()] if (toolingRelease == null) { - LOG.warn("Could not determine Azure Functions core tools release for version: '$azureFunctionsVersion'") + LOG.warn("Could not determine Functions tooling release for version: '$azureFunctionsVersion'") return null } + LOG.trace { "Latest Functions tooling release for version '$azureFunctionsVersion' is '$toolingRelease'" } + return toolingRelease } - private fun getReleaseDownloadRoot(): Path? { + private fun getPathForLatestFunctionsToolingRelease(toolingRelease: FunctionsToolingRelease): Path? { val settings = AzureFunctionSettings.getInstance() val coreToolsDownloadFolder = settings.functionDownloadPath - return if (coreToolsDownloadFolder.isNotEmpty()) Path(coreToolsDownloadFolder) - else null - } + val downloadRoot = + if (coreToolsDownloadFolder.isNotEmpty()) Path(coreToolsDownloadFolder) + else null - private fun getPathForLatestFunctionsToolingRelease(toolingRelease: FunctionsToolingRelease): Path? { - val downloadRoot = getReleaseDownloadRoot() - return downloadRoot?.resolve(toolingRelease.functionsVersion)?.resolve(toolingRelease.releaseTag) + val path = downloadRoot?.resolve(toolingRelease.functionsVersion)?.resolve(toolingRelease.releaseTag) + + LOG.trace { "Path for the Latest Functions tooling release is $path" } + + return path } private fun Release.findCoreToolsRelease(releaseFilter: FunctionToolingFeedFilter) = @@ -232,6 +241,7 @@ class FunctionsToolingFeedService : Disposable { .firstOrNull() private fun setExecutablePermissionsForCoreTools(coreToolsExecutable: Path) { + LOG.trace { "Setting permissions for $coreToolsExecutable" } coreToolsExecutable.setPosixFilePermissions( setOf( PosixFilePermission.OWNER_EXECUTE,