mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-78762: Activate conda in Powershell.
We used to use `Invoke-Expression` but then migrated to `&`. However, a conda activation script is a command (code block), not a file, so we need to use `Invoke-Expression` as '&' doesn't support it. We check if a file exists, and if it does -- we use '&' which is safe and fast. We use `Invoke-Expression` otherwise. Merge-request: IJ-MR-158505 Merged-by: Ilya Kazakevich <ilya.kazakevich@jetbrains.com> GitOrigin-RevId: ea0772b3f5f9641a85b542903c44c3b78aed0715
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a6ff3d6fbc
commit
ca46fea6b0
@@ -16,8 +16,12 @@ Get-ChildItem env:_INTELLIJ_FORCE_PREPEND_* | ForEach-Object {
|
||||
}
|
||||
# `JEDITERM_SOURCE` is executed in its own scope now. That means, it can only run code, and export env vars. It can't export PS variables.
|
||||
# It might be better to source it. See MSDN for the difference between "Call operator &" and "Script scope and dot sourcing"
|
||||
if (($Env:JEDITERM_SOURCE -ne $null) -and (Test-Path $Env:JEDITERM_SOURCE)) {
|
||||
& $Env:JEDITERM_SOURCE
|
||||
if ($Env:JEDITERM_SOURCE -ne $null) {
|
||||
if (Test-Path "$Env:JEDITERM_SOURCE" -ErrorAction SilentlyContinue) {
|
||||
& "$Env:JEDITERM_SOURCE"
|
||||
} else { # If file doesn't exist it might be a script
|
||||
Invoke-Expression "$Env:JEDITERM_SOURCE"
|
||||
}
|
||||
Remove-Item "env:JEDITERM_SOURCE"
|
||||
}
|
||||
|
||||
|
||||
+2
@@ -13,5 +13,7 @@
|
||||
<orderEntry type="module" module-name="intellij.python.community.testFramework.testEnv.conda" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit5" level="project" />
|
||||
<orderEntry type="library" scope="TEST" name="jetbrains-annotations" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.execution" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core" scope="TEST" />
|
||||
</component>
|
||||
</module>
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.python.community.junit5Tests.framework.conda
|
||||
|
||||
import com.intellij.execution.processTools.getResultStdoutStr
|
||||
import com.jetbrains.python.psi.LanguageLevel
|
||||
import com.jetbrains.python.sdk.flavors.conda.NewCondaEnvRequest
|
||||
import com.jetbrains.python.sdk.flavors.conda.PyCondaCommand
|
||||
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnv
|
||||
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnvIdentity
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.pathString
|
||||
|
||||
@ApiStatus.Internal
|
||||
/**
|
||||
* Create conda env in [pathToCreateNewEnvIn] using [existingEnv] as a base
|
||||
*/
|
||||
suspend fun createCondaEnv(
|
||||
existingEnv: PyCondaEnv,
|
||||
pathToCreateNewEnvIn: Path,
|
||||
): PyCondaEnv {
|
||||
val process = PyCondaEnv.createEnv(
|
||||
PyCondaCommand(existingEnv.fullCondaPathOnTarget, null),
|
||||
NewCondaEnvRequest.EmptyUnnamedEnv(LanguageLevel.PYTHON311, pathToCreateNewEnvIn.pathString)
|
||||
).getOrThrow()
|
||||
process.getResultStdoutStr().getOrThrow()
|
||||
|
||||
val env = PyCondaEnv(PyCondaEnvIdentity.UnnamedEnv(pathToCreateNewEnvIn.pathString, false), existingEnv.fullCondaPathOnTarget)
|
||||
return env
|
||||
}
|
||||
@@ -25,5 +25,7 @@
|
||||
<orderEntry type="library" scope="TEST" name="hamcrest" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.python.community.testFramework.testEnv" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.python.community.impl.venv" scope="TEST" />
|
||||
<orderEntry type="module" module-name="intellij.python.community.junit5Tests.framework.conda" scope="TEST" />
|
||||
<orderEntry type="library" scope="TEST" name="JUnit5Params" level="project" />
|
||||
</component>
|
||||
</module>
|
||||
+45
-11
@@ -2,19 +2,27 @@
|
||||
package com.intellij.python.junit5Tests.env.terminal
|
||||
|
||||
import com.intellij.execution.configurations.PathEnvironmentVariableUtil
|
||||
import com.intellij.openapi.application.edtWriteAction
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||
import com.intellij.openapi.projectRoots.Sdk
|
||||
import com.intellij.openapi.roots.ModuleRootModificationUtil
|
||||
import com.intellij.platform.eel.EelExecApi
|
||||
import com.intellij.platform.eel.getOrThrow
|
||||
import com.intellij.platform.eel.provider.localEel
|
||||
import com.intellij.platform.eel.provider.utils.readWholeText
|
||||
import com.intellij.platform.eel.provider.utils.sendWholeText
|
||||
import com.intellij.python.community.impl.venv.tests.pyVenvFixture
|
||||
import com.intellij.python.junit5Tests.framework.env.PyEnvTestCase
|
||||
import com.intellij.python.community.junit5Tests.framework.conda.CondaEnv
|
||||
import com.intellij.python.community.junit5Tests.framework.conda.PyEnvTestCaseWithConda
|
||||
import com.intellij.python.community.junit5Tests.framework.conda.createCondaEnv
|
||||
import com.intellij.python.junit5Tests.framework.env.pySdkFixture
|
||||
import com.intellij.python.terminal.PyVirtualEnvTerminalCustomizer
|
||||
import com.intellij.testFramework.common.timeoutRunBlocking
|
||||
import com.intellij.testFramework.junit5.fixture.moduleFixture
|
||||
import com.intellij.testFramework.junit5.fixture.projectFixture
|
||||
import com.intellij.testFramework.junit5.fixture.tempPathFixture
|
||||
import com.jetbrains.python.sdk.flavors.conda.PyCondaEnv
|
||||
import com.jetbrains.python.sdk.persist
|
||||
import com.jetbrains.python.venvReader.VirtualEnvReader
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -24,11 +32,15 @@ import org.jetbrains.plugins.terminal.ShellStartupOptions
|
||||
import org.jetbrains.plugins.terminal.runner.LocalShellIntegrationInjector
|
||||
import org.jetbrains.plugins.terminal.util.ShellIntegration
|
||||
import org.jetbrains.plugins.terminal.util.ShellType
|
||||
import org.junit.jupiter.api.AfterEach
|
||||
import org.junit.jupiter.api.Assertions
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs
|
||||
import org.junit.jupiter.api.condition.OS
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import org.junit.jupiter.params.ParameterizedTest
|
||||
import org.junit.jupiter.params.provider.ValueSource
|
||||
import java.io.IOException
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.name
|
||||
import kotlin.io.path.pathString
|
||||
@@ -39,7 +51,7 @@ private const val WHERE_EXE = "where.exe"
|
||||
/**
|
||||
* Run `powershell.exe` with a venv activation script and make sure there are no errors and python is correct
|
||||
*/
|
||||
@PyEnvTestCase
|
||||
@PyEnvTestCaseWithConda
|
||||
class PyVirtualEnvTerminalCustomizerTest {
|
||||
private val projectFixture = projectFixture()
|
||||
private val tempDirFixture = tempPathFixture(prefix = "some dir with spaces")
|
||||
@@ -52,15 +64,38 @@ class PyVirtualEnvTerminalCustomizerTest {
|
||||
moduleFixture = moduleFixture
|
||||
)
|
||||
|
||||
private var sdkToDelete: Sdk? = null
|
||||
|
||||
@AfterEach
|
||||
fun tearDown(): Unit = timeoutRunBlocking {
|
||||
sdkToDelete?.let { sdk ->
|
||||
edtWriteAction {
|
||||
ProjectJdkTable.getInstance().removeJdk(sdk)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val powerShell =
|
||||
PathEnvironmentVariableUtil.findInPath("powershell.exe")?.toPath()
|
||||
?: Path((System.getenv("SystemRoot") ?: "c:\\windows"), "system32", "WindowsPowerShell", "v1.0", "powershell.exe")
|
||||
|
||||
@EnabledOnOs(value = [OS.WINDOWS])
|
||||
@Test
|
||||
fun powershellActivationTest(): Unit = timeoutRunBlocking(10.minutes) {
|
||||
val pythonBinary = VirtualEnvReader.Instance.findPythonInPythonRoot(tempDirFixture.get())!!
|
||||
@ParameterizedTest
|
||||
@ValueSource(booleans = [true, false])
|
||||
fun powershellActivationTest(useConda: Boolean, @CondaEnv condaEnv: PyCondaEnv, @TempDir path: Path): Unit = timeoutRunBlocking(10.minutes) {
|
||||
val (pythonBinary, venvDirName) =
|
||||
if (useConda) {
|
||||
val envDir = path.resolve("some path with spaces")
|
||||
val sdk = createCondaEnv(condaEnv, envDir).createSdkFromThisEnv(null, emptyList())
|
||||
sdkToDelete = sdk
|
||||
sdk.persist()
|
||||
ModuleRootModificationUtil.setModuleSdk(moduleFixture.get(), sdk)
|
||||
Pair(Path(sdk.homePath!!), envDir.toRealPath().pathString)
|
||||
}
|
||||
else {
|
||||
val venv = VirtualEnvReader.Instance.findPythonInPythonRoot(tempDirFixture.get())!!
|
||||
Pair(venv, tempDirFixture.get().name)
|
||||
}
|
||||
|
||||
// binary might be like ~8.3, we need to expand it as venv might report both
|
||||
val pythonBinaryReal = try {
|
||||
@@ -69,7 +104,7 @@ class PyVirtualEnvTerminalCustomizerTest {
|
||||
catch (_: IOException) {
|
||||
pythonBinary
|
||||
}
|
||||
val shellOptions = getShellStartupOptions()
|
||||
val shellOptions = getShellStartupOptions(pythonBinary.parent)
|
||||
val command = shellOptions.shellCommand!!
|
||||
val exe = command[0]
|
||||
val args = if (command.size == 1) emptyList() else command.subList(1, command.size)
|
||||
@@ -95,8 +130,7 @@ class PyVirtualEnvTerminalCustomizerTest {
|
||||
|
||||
assertThat("We ran `$where`, so we there should be python path", output,
|
||||
anyOf(hasItem(pythonBinary.pathString), hasItem(pythonBinaryReal.pathString)))
|
||||
val vendDirName = tempDirFixture.get().name
|
||||
assertThat("There must be a line with ($vendDirName)", output, hasItem(containsString("($vendDirName)")))
|
||||
assertThat("There must be a line with ($venvDirName)", output, hasItem(containsString("($venvDirName)")))
|
||||
|
||||
process.exitCode.await()
|
||||
}
|
||||
@@ -107,12 +141,12 @@ class PyVirtualEnvTerminalCustomizerTest {
|
||||
}
|
||||
}
|
||||
|
||||
private fun getShellStartupOptions(): ShellStartupOptions {
|
||||
private fun getShellStartupOptions(workDir: Path): ShellStartupOptions {
|
||||
val sut = PyVirtualEnvTerminalCustomizer()
|
||||
val env = mutableMapOf<String, String>()
|
||||
val command = sut.customizeCommandAndEnvironment(
|
||||
projectFixture.get(),
|
||||
tempDirFixture.get().pathString,
|
||||
workDir.pathString,
|
||||
arrayOf(powerShell.pathString),
|
||||
env)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user