From 395ad4a4df13b49eceba7d39e8a5548e09202cae Mon Sep 17 00:00:00 2001 From: Aviram Hassan Date: Tue, 2 Apr 2024 16:09:49 +0300 Subject: [PATCH] support unset env feature (#253) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * support unset env feature * finished * build error * Apply suggestions from code review Co-authored-by: Michał Smolarek <34063647+Razz4780@users.noreply.github.com> * Fixed removing env --------- Co-authored-by: Michał Smolarek <34063647+Razz4780@users.noreply.github.com> Co-authored-by: Razz4780 --- changelog.d/+support-unset-feature.added.md | 1 + .../com/metalbear/mirrord/MirrordApi.kt | 6 +++- .../metalbear/mirrord/MirrordExecManager.kt | 6 ++-- .../mirrord/MirrordNpmExecutionListener.kt | 11 +++++-- .../goland/GolandRunConfigurationExtension.kt | 11 +++++-- .../idea/IdeaRunConfigurationExtension.kt | 30 ++++++++++++------- .../nodejs/NodeRunConfigurationExtension.kt | 11 +++++-- .../pycharm/PythonCommandLineProvider.kt | 9 ++++-- .../PythonRunConfigurationExtension.kt | 9 ++++-- .../rider/RiderPatchCommandLineExtension.kt | 8 +++-- .../RubyMineRunConfigurationExtension.kt | 15 ++++++---- .../tomcat/TomcatExecutionListener.kt | 15 ++++++---- 12 files changed, 94 insertions(+), 38 deletions(-) create mode 100644 changelog.d/+support-unset-feature.added.md diff --git a/changelog.d/+support-unset-feature.added.md b/changelog.d/+support-unset-feature.added.md new file mode 100644 index 00000000..852ae913 --- /dev/null +++ b/changelog.d/+support-unset-feature.added.md @@ -0,0 +1 @@ +support unset env feature \ No newline at end of file diff --git a/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordApi.kt b/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordApi.kt index 9cac1161..ed66656a 100644 --- a/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordApi.kt +++ b/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordApi.kt @@ -92,7 +92,11 @@ data class IdeMessage(val id: String, val level: NotificationLevel, val text: St data class Error(val message: String, val severity: String, val causes: List, val help: String, val labels: List, val related: List) -data class MirrordExecution(val environment: MutableMap, @SerializedName("patched_path") val patchedPath: String?) +data class MirrordExecution( + val environment: MutableMap, + @SerializedName("patched_path") val patchedPath: String?, + @SerializedName("env_to_unset") val envToUnset: List? +) /** * Wrapper around Gson for parsing messages from the mirrord binary. diff --git a/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordExecManager.kt b/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordExecManager.kt index 00df5b20..3795aecf 100644 --- a/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordExecManager.kt +++ b/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordExecManager.kt @@ -98,7 +98,7 @@ class MirrordExecManager(private val service: MirrordProjectService) { executable: String?, product: String, projectEnvVars: Map? - ): Pair, String?>? { + ): MirrordExecution? { MirrordLogger.logger.debug("MirrordExecManager.start") val explicitlyEnabled = projectEnvVars?.any { (key, value) -> key == "MIRRORD_ACTIVE" && value == "1" } ?: false if (!service.enabled && !explicitlyEnabled) { @@ -195,7 +195,7 @@ class MirrordExecManager(private val service: MirrordProjectService) { MirrordLogger.logger.debug("MirrordExecManager.start: executionInfo: $executionInfo") executionInfo.environment["MIRRORD_IGNORE_DEBUGGER_PORTS"] = "35000-65535" - return Pair(executionInfo.environment, executionInfo.patchedPath) + return executionInfo } /** @@ -207,7 +207,7 @@ class MirrordExecManager(private val service: MirrordProjectService) { var wsl: WSLDistribution? = null var executable: String? = null - fun start(): Pair, String?>? { + fun start(): MirrordExecution? { return try { manager.start(wsl, executable, product, extraEnvVars) } catch (e: MirrordError) { diff --git a/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordNpmExecutionListener.kt b/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordNpmExecutionListener.kt index dea55a94..cb2c80fa 100644 --- a/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordNpmExecutionListener.kt +++ b/modules/core/src/main/kotlin/com/metalbear/mirrord/MirrordNpmExecutionListener.kt @@ -43,10 +43,15 @@ class MirrordNpmExecutionListener : ExecutionListener { service.execManager.wrapper("JS", executionGuard.originEnv).apply { wsl = wslDistribution executable = executablePath - }.start()?.let { (newEnv, patchedPath) -> - runSettings.envs = executionGuard.originEnv + newEnv + }.start()?.let { executionInfo -> + var envs = (executionGuard.originEnv + executionInfo.environment) - patchedPath?.let { + executionInfo.envToUnset?.let { envToUnset -> + envs = envs.filterKeys { !envToUnset.contains(it) } + } + runSettings.envs = envs + + executionInfo.patchedPath?.let { executionGuard.originPackageManagerPackageRef = runSettings.packageManagerPackageRef runSettings.packageManagerPackagePath = it } diff --git a/modules/products/goland/src/main/kotlin/com/metalbear/mirrord/products/goland/GolandRunConfigurationExtension.kt b/modules/products/goland/src/main/kotlin/com/metalbear/mirrord/products/goland/GolandRunConfigurationExtension.kt index bd97ea62..37fb0a42 100644 --- a/modules/products/goland/src/main/kotlin/com/metalbear/mirrord/products/goland/GolandRunConfigurationExtension.kt +++ b/modules/products/goland/src/main/kotlin/com/metalbear/mirrord/products/goland/GolandRunConfigurationExtension.kt @@ -48,11 +48,18 @@ class GolandRunConfigurationExtension : GoRunConfigurationExtension() { service.execManager.wrapper("goland", configuration.getCustomEnvironment()).apply { this.wsl = wsl - }.start()?.first?.let { env -> - for (entry in env.entries.iterator()) { + }.start()?.let { executionInfo -> + + for (entry in executionInfo.environment.entries.iterator()) { cmdLine.addEnvironmentVariable(entry.key, entry.value) } cmdLine.addEnvironmentVariable("MIRRORD_SKIP_PROCESSES", "dlv;debugserver;go") + + executionInfo.envToUnset?.let { keys -> + for (key in keys.iterator()) { + cmdLine.removeEnvironmentVariable(key) + } + } } } super.patchCommandLine(configuration, runnerSettings, cmdLine, runnerId, state, commandLineType) diff --git a/modules/products/idea/src/main/kotlin/com/metalbear/mirrord/products/idea/IdeaRunConfigurationExtension.kt b/modules/products/idea/src/main/kotlin/com/metalbear/mirrord/products/idea/IdeaRunConfigurationExtension.kt index f04adfbb..75134c30 100644 --- a/modules/products/idea/src/main/kotlin/com/metalbear/mirrord/products/idea/IdeaRunConfigurationExtension.kt +++ b/modules/products/idea/src/main/kotlin/com/metalbear/mirrord/products/idea/IdeaRunConfigurationExtension.kt @@ -72,19 +72,27 @@ class IdeaRunConfigurationExtension : RunConfigurationExtension() { params.env } - val mirrordEnv = service.execManager.wrapper("idea", extraEnv).apply { + service.execManager.wrapper("idea", extraEnv).apply { this.wsl = wsl - }.start()?.first?.let { it + mapOf(Pair("MIRRORD_DETECT_DEBUGGER_PORT", "javaagent")) }.orEmpty() - - params.env = params.env + mirrordEnv - runningProcessEnvs[configuration.project] = params.env.toMap() - - // Gradle support (and external system configuration) - if (configuration is ExternalSystemRunConfiguration) { - runningProcessEnvs[configuration.project] = configuration.settings.env.toMap() - configuration.settings.env = configuration.settings.env + mirrordEnv + }.start()?.let { executionInfo -> + val mirrordEnv = executionInfo.environment + mapOf(Pair("MIRRORD_DETECT_DEBUGGER_PORT", "javaagent")) + params.env = params.env + mirrordEnv + executionInfo.envToUnset?.let { keys -> + params.env = params.env.filterKeys { !keys.contains(it) } + } + runningProcessEnvs[configuration.project] = params.env.toMap() + + // Gradle support (and external system configuration) + if (configuration is ExternalSystemRunConfiguration) { + runningProcessEnvs[configuration.project] = configuration.settings.env.toMap() + var env = configuration.settings.env + mirrordEnv + executionInfo.envToUnset?.let { keys -> + env = env.filterKeys { !keys.contains(it) } + } + configuration.settings.env = configuration.settings.env + mirrordEnv + } + MirrordLogger.logger.debug("setting env and finishing") } - MirrordLogger.logger.debug("setting env and finishing") } /** diff --git a/modules/products/nodejs/src/main/kotlin/com/metalbear/mirrord/products/nodejs/NodeRunConfigurationExtension.kt b/modules/products/nodejs/src/main/kotlin/com/metalbear/mirrord/products/nodejs/NodeRunConfigurationExtension.kt index 0c3eecb5..680358dd 100644 --- a/modules/products/nodejs/src/main/kotlin/com/metalbear/mirrord/products/nodejs/NodeRunConfigurationExtension.kt +++ b/modules/products/nodejs/src/main/kotlin/com/metalbear/mirrord/products/nodejs/NodeRunConfigurationExtension.kt @@ -47,8 +47,15 @@ class NodeRunConfigurationExtension : AbstractNodeRunConfigurationExtension() { service.execManager.wrapper("nodejs", extraEnvVars).apply { this.wsl = wsl - }.start()?.first?.forEach { (key, value) -> - targetRun.commandLineBuilder.addEnvironmentVariable(key, value) + }.start()?.let { executionInfo -> + executionInfo.environment.forEach { (key, value) -> + targetRun.commandLineBuilder.addEnvironmentVariable(key, value) + } + executionInfo.envToUnset?.let { keys -> + for (key in keys.iterator()) { + targetRun.commandLineBuilder.removeEnvironmentVariable(key) + } + } } } } diff --git a/modules/products/pycharm/src/main/kotlin/com/metalbear/mirrord/products/pycharm/PythonCommandLineProvider.kt b/modules/products/pycharm/src/main/kotlin/com/metalbear/mirrord/products/pycharm/PythonCommandLineProvider.kt index 88857720..fd96b7a3 100644 --- a/modules/products/pycharm/src/main/kotlin/com/metalbear/mirrord/products/pycharm/PythonCommandLineProvider.kt +++ b/modules/products/pycharm/src/main/kotlin/com/metalbear/mirrord/products/pycharm/PythonCommandLineProvider.kt @@ -30,10 +30,15 @@ class PythonCommandLineProvider : PythonCommandLineTargetEnvironmentProvider { service.execManager.wrapper("pycharm", runParams.getEnvs()).apply { this.wsl = wsl - }.start()?.first?.let { env -> - for (entry in env.entries.iterator()) { + }.start()?.let { executionInfo -> + for (entry in executionInfo.environment.entries.iterator()) { pythonExecution.addEnvironmentVariable(entry.key, entry.value) } + + for (key in executionInfo.envToUnset.orEmpty()) { + pythonExecution.envs.remove(key) + } + pythonExecution.addEnvironmentVariable("MIRRORD_DETECT_DEBUGGER_PORT", "pydevd") } } diff --git a/modules/products/pycharm/src/main/kotlin/com/metalbear/mirrord/products/pycharm/PythonRunConfigurationExtension.kt b/modules/products/pycharm/src/main/kotlin/com/metalbear/mirrord/products/pycharm/PythonRunConfigurationExtension.kt index f26c8497..424b2a06 100644 --- a/modules/products/pycharm/src/main/kotlin/com/metalbear/mirrord/products/pycharm/PythonRunConfigurationExtension.kt +++ b/modules/products/pycharm/src/main/kotlin/com/metalbear/mirrord/products/pycharm/PythonRunConfigurationExtension.kt @@ -38,10 +38,15 @@ class PythonRunConfigurationExtension : PythonRunConfigurationExtension() { service.execManager.wrapper("pycharm", currentEnv).apply { this.wsl = wsl - }.start()?.first?.let { env -> - for (entry in env.entries.iterator()) { + }.start()?.let { executionInfo -> + for (entry in executionInfo.environment.entries.iterator()) { currentEnv[entry.key] = entry.value } + executionInfo.envToUnset?.let { envToUnset -> + for (key in envToUnset.iterator()) { + currentEnv.remove(key) + } + } } currentEnv["MIRRORD_DETECT_DEBUGGER_PORT"] = "pydevd" diff --git a/modules/products/rider/src/main/kotlin/com/metalbear/mirrord/products/rider/RiderPatchCommandLineExtension.kt b/modules/products/rider/src/main/kotlin/com/metalbear/mirrord/products/rider/RiderPatchCommandLineExtension.kt index 093d3afe..cda7d98e 100644 --- a/modules/products/rider/src/main/kotlin/com/metalbear/mirrord/products/rider/RiderPatchCommandLineExtension.kt +++ b/modules/products/rider/src/main/kotlin/com/metalbear/mirrord/products/rider/RiderPatchCommandLineExtension.kt @@ -33,10 +33,14 @@ class RiderPatchCommandLineExtension : PatchCommandLineExtension { service.execManager.wrapper("rider", commandLine.environment).apply { this.wsl = wsl - }.start()?.first?.let { env -> - for (entry in env.entries.iterator()) { + }.start()?.let { executionInfo -> + for (entry in executionInfo.environment.entries.iterator()) { commandLine.withEnvironment(entry.key, entry.value) } + + for (key in executionInfo.envToUnset.orEmpty()) { + commandLine.environment.remove(key) + } } } diff --git a/modules/products/rubymine/src/main/kotlin/com/metalbear/mirrord/products/rubymine/RubyMineRunConfigurationExtension.kt b/modules/products/rubymine/src/main/kotlin/com/metalbear/mirrord/products/rubymine/RubyMineRunConfigurationExtension.kt index 53561cad..ca553a7f 100644 --- a/modules/products/rubymine/src/main/kotlin/com/metalbear/mirrord/products/rubymine/RubyMineRunConfigurationExtension.kt +++ b/modules/products/rubymine/src/main/kotlin/com/metalbear/mirrord/products/rubymine/RubyMineRunConfigurationExtension.kt @@ -12,7 +12,9 @@ import com.metalbear.mirrord.MirrordError import com.metalbear.mirrord.MirrordProjectService import org.jetbrains.plugins.ruby.ruby.run.configuration.AbstractRubyRunConfiguration import org.jetbrains.plugins.ruby.ruby.run.configuration.RubyRunConfigurationExtension -import kotlin.io.path.* +import kotlin.io.path.createTempFile +import kotlin.io.path.pathString +import kotlin.io.path.writeText class RubyMineRunConfigurationExtension : RubyRunConfigurationExtension() { @@ -48,15 +50,18 @@ class RubyMineRunConfigurationExtension : RubyRunConfigurationExtension() { if (isMac) { this.executable = cmdLine.exePath } - }.start()?.let { (mirrordEnv, patched) -> + }.start()?.let { executionInfo -> // this is the env the Ruby app and the layer see, at least with RVM. - cmdLine.withEnvironment(mirrordEnv) + cmdLine.withEnvironment(executionInfo.environment) - if (isMac && patched !== null) { - cmdLine.exePath = patched + for (key in executionInfo.envToUnset.orEmpty()) { + cmdLine.environment.remove(key) } if (isMac) { + executionInfo.patchedPath?.let { + cmdLine.exePath = it + } // TODO: would be nice to have a more robust RVM detection mechanism. val isRvm = cmdLine.exePath.contains("/.rvm/rubies/") if (isRvm) { diff --git a/modules/products/tomcat/src/main/kotlin/com/metalbear/mirrord/products/tomcat/TomcatExecutionListener.kt b/modules/products/tomcat/src/main/kotlin/com/metalbear/mirrord/products/tomcat/TomcatExecutionListener.kt index b0cf1bc3..cfe897bd 100644 --- a/modules/products/tomcat/src/main/kotlin/com/metalbear/mirrord/products/tomcat/TomcatExecutionListener.kt +++ b/modules/products/tomcat/src/main/kotlin/com/metalbear/mirrord/products/tomcat/TomcatExecutionListener.kt @@ -138,7 +138,7 @@ class TomcatExecutionListener : ExecutionListener { MirrordLogger.logger.debug("processStartScheduled tomcat") getConfig(env)?.let { config -> MirrordLogger.logger.debug("processStartScheduled: got tomcat config") - val envVars = config.envVariables + var envVars = config.envVariables val envVarsMap = envVars.map { it.NAME to it.VALUE }.toMap() val service = env.project.service() @@ -168,19 +168,24 @@ class TomcatExecutionListener : ExecutionListener { service.execManager.wrapper("idea", envVarsMap).apply { this.wsl = wsl this.executable = scriptAndArgs?.command - }.start()?.let { (env, patchedPath) -> - MirrordLogger.logger.debug("got execution info for tomcat - env: $env, patchedPath: $patchedPath") + }.start()?.let { executionInfo -> // `MIRRORD_IGNORE_DEBUGGER_PORTS` should allow clean shutdown of the app // even if `outgoing` feature is enabled. - val mirrordEnv = env + mapOf(Pair("MIRRORD_DETECT_DEBUGGER_PORT", "javaagent"), Pair("MIRRORD_IGNORE_DEBUGGER_PORTS", getTomcatServerPort())) + val mirrordEnv = executionInfo.environment + mapOf(Pair("MIRRORD_DETECT_DEBUGGER_PORT", "javaagent"), Pair("MIRRORD_IGNORE_DEBUGGER_PORTS", getTomcatServerPort())) val savedData = SavedConfigData(envVars.toList(), null) envVars.addAll(mirrordEnv.map { (k, v) -> EnvironmentVariable(k, v, false) }) + + executionInfo.envToUnset?.let { envToUnset -> + envVars = envVars.filter { + !envToUnset.contains(it.name) + } + } config.setEnvironmentVariables(envVars) if (SystemInfo.isMac) { MirrordLogger.logger.debug("isMac, patching SIP.") - patchedPath?.let { + executionInfo.patchedPath?.let { MirrordLogger.logger.debug("patchedPath is not null: $it, meaning original was SIP") savedData.scriptInfo = startupInfo if (config.startupInfo.USE_DEFAULT) {