pinokiod 7.5.34 → 7.5.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/kernel/bin/conda.js +99 -103
- package/package.json +1 -1
- package/test/conda-bin.test.js +34 -93
package/kernel/bin/conda.js
CHANGED
|
@@ -69,76 +69,98 @@ const LEGACY_SSL_CERT_DIR_HOOK_FILES = [
|
|
|
69
69
|
"zz_pinokio_unset_ssl_cert_dir-win.ps1",
|
|
70
70
|
"zz_pinokio_unset_ssl_cert_dir-win.sh",
|
|
71
71
|
]
|
|
72
|
-
const
|
|
73
|
-
"
|
|
74
|
-
"site-packages",
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
'
|
|
102
|
-
"
|
|
103
|
-
"
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
72
|
+
const WINDOWS_CONDA_ACTIVATE_RELATIVE_PATHS = [
|
|
73
|
+
path.join("condabin", "_conda_activate.bat"),
|
|
74
|
+
path.join("Lib", "site-packages", "conda", "shell", "condabin", "_conda_activate.bat"),
|
|
75
|
+
]
|
|
76
|
+
const WINDOWS_CONDA_ACTIVATE_BAT = [
|
|
77
|
+
":: Copyright (C) 2012 Anaconda, Inc",
|
|
78
|
+
":: SPDX-License-Identifier: BSD-3-Clause",
|
|
79
|
+
":: Helper routine for activation, deactivation, and reactivation.",
|
|
80
|
+
"@ECHO OFF",
|
|
81
|
+
"SETLOCAL",
|
|
82
|
+
"",
|
|
83
|
+
":: Generate a unique temporary filename using a GUID to support parallel workflows",
|
|
84
|
+
":: (e.g., `start /b conda run ...`). %RANDOM% is insufficient because processes",
|
|
85
|
+
":: started simultaneously get identical time-based seeds, producing collisions.",
|
|
86
|
+
":: See: https://devblogs.microsoft.com/oldnewthing/20100617-00/?p=13673",
|
|
87
|
+
"FOR /F \"delims=\" %%G IN ('powershell -NoProfile -Command \"[guid]::NewGuid()\"') DO SET \"__conda_guid=%%G\"",
|
|
88
|
+
"SET \"__conda_tmp=%TEMP%\\__conda_tmp_%__conda_guid%.txt\"",
|
|
89
|
+
"",
|
|
90
|
+
":: Run conda command and get its output",
|
|
91
|
+
":: WARNING: This cannot be simplified into a FOR /F parsing loop because of the way",
|
|
92
|
+
":: MSDOS associates the outer quotes for usebackq. E.g., the following:",
|
|
93
|
+
":: `\"%CONDA_EXE%\" shell.cmd.exe activate \"name\"`",
|
|
94
|
+
":: Which results in the following gibberish being run:",
|
|
95
|
+
":: %CONDA_EXE%\" shell.cmd.exe activate \"environment",
|
|
96
|
+
":: Producing an error like:",
|
|
97
|
+
":: The filename, directory name, or volume label syntax is incorrect.",
|
|
98
|
+
":: Instead we run the command and store the output for subsequent processing.",
|
|
99
|
+
"\"%CONDA_EXE%\" %_CE_M% %_CE_CONDA% shell.cmd.exe %* > \"%__conda_tmp%\"",
|
|
100
|
+
"IF NOT EXIST \"%__conda_tmp%\" (",
|
|
101
|
+
" ECHO ERROR: Failed to create temp file for 'conda %*'.>&2",
|
|
102
|
+
" ECHO.>&2",
|
|
103
|
+
" ECHO This is likely a TEMP directory issue>&2",
|
|
104
|
+
" ECHO ^(permissions, disk space, or invalid path^).>&2",
|
|
105
|
+
" ECHO.>&2",
|
|
106
|
+
" ECHO Ensure TEMP or TMP environment variables point to a writable location.>&2",
|
|
107
|
+
" ECHO See: https://docs.conda.io/projects/conda/en/stable/user-guide/troubleshooting.html#temp-file-errors>&2",
|
|
108
|
+
" ENDLOCAL & EXIT /B 1",
|
|
109
|
+
") ELSE IF %ERRORLEVEL% NEQ 0 (",
|
|
110
|
+
" ECHO ERROR: 'conda %*' exited with code %ERRORLEVEL%.>&2",
|
|
111
|
+
" CALL :DELETE \"%__conda_tmp%\"",
|
|
112
|
+
" ENDLOCAL & EXIT /B 2",
|
|
113
|
+
")",
|
|
114
|
+
"",
|
|
115
|
+
":: Check if conda produced output",
|
|
116
|
+
"FOR /F \"delims=\" %%T IN (%__conda_tmp%) DO (",
|
|
117
|
+
" :: T = \"%TEMP%\\<uuid>.env\"",
|
|
118
|
+
" IF NOT EXIST \"%%T\" (",
|
|
119
|
+
" ECHO ERROR: Activation file missing for 'conda %*'.>&2",
|
|
120
|
+
" CALL :DELETE \"%__conda_tmp%\"",
|
|
121
|
+
" ENDLOCAL & EXIT /B 3",
|
|
122
|
+
" ) ELSE ENDLOCAL & @CALL :PINOKIO_APPLY_CONDA_ENV \"%%T\" \"%__conda_tmp%\" & @GOTO :EOF",
|
|
123
|
+
")",
|
|
124
|
+
"",
|
|
125
|
+
":: If we get here, the FOR loop never ran which means no output",
|
|
126
|
+
"ECHO ERROR: No output from 'conda %*'.>&2",
|
|
127
|
+
"CALL :DELETE \"%__conda_tmp%\"",
|
|
128
|
+
"ENDLOCAL & EXIT /B 5",
|
|
129
|
+
"",
|
|
130
|
+
":PINOKIO_APPLY_CONDA_ENV",
|
|
131
|
+
"@ECHO OFF",
|
|
132
|
+
"@FOR /F \"tokens=1,* delims==\" %%A IN (%~1) DO (",
|
|
133
|
+
"@IF \"%CONDA_DEBUG%\" == \"1\" ECHO DEBUG: \"%%A=%%B\">&2",
|
|
134
|
+
"@IF \"%%A\"==\"_CONDA_SCRIPT\" (",
|
|
135
|
+
"@CALL \"%%B\" || (",
|
|
136
|
+
"@ECHO ERROR: Activation script \"%%B\" failed with code %ERRORLEVEL%.>&2",
|
|
137
|
+
"@CALL :DELETE \"%~1\"",
|
|
138
|
+
"@CALL :DELETE \"%~2\"",
|
|
139
|
+
"@ECHO ON",
|
|
140
|
+
"@EXIT /B 4",
|
|
141
|
+
")",
|
|
142
|
+
") ELSE IF \"%%B\"==\"\" (",
|
|
143
|
+
"@SET \"%%A=\"",
|
|
144
|
+
") ELSE (",
|
|
145
|
+
"@SET \"%%A=%%B\"",
|
|
146
|
+
")",
|
|
147
|
+
")",
|
|
148
|
+
"@CALL :DELETE \"%~1\"",
|
|
149
|
+
"@CALL :DELETE \"%~2\"",
|
|
150
|
+
"@ECHO ON",
|
|
151
|
+
"@EXIT /B 0",
|
|
152
|
+
"",
|
|
153
|
+
":: Routine to delete a temp file if CONDA_DEBUG is not set",
|
|
154
|
+
":: usage: call :DELETE \"path/to/file\"",
|
|
155
|
+
":DELETE",
|
|
156
|
+
"IF \"%CONDA_DEBUG%\" == \"1\" (",
|
|
157
|
+
" ECHO DEBUG: Retaining temporary file \"%~1\".>&2",
|
|
158
|
+
") ELSE IF EXIST \"%~1\" (",
|
|
159
|
+
" DEL /F /Q \"%~1\" 2>NUL",
|
|
160
|
+
")",
|
|
161
|
+
"GOTO :EOF",
|
|
162
|
+
"",
|
|
163
|
+
].join("\r\n")
|
|
142
164
|
|
|
143
165
|
class Conda {
|
|
144
166
|
description = "Pinokio uses Conda to install various useful programs in an isolated manner."
|
|
@@ -231,41 +253,15 @@ class Conda {
|
|
|
231
253
|
}
|
|
232
254
|
}
|
|
233
255
|
}
|
|
234
|
-
async
|
|
256
|
+
async ensureWindowsCondaActivateBat() {
|
|
235
257
|
if (this.kernel.platform !== "win32" || !(await this.hasCondaMeta())) {
|
|
236
258
|
return
|
|
237
259
|
}
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
} catch (error) {
|
|
243
|
-
if (error && error.code === "ENOENT") {
|
|
244
|
-
return
|
|
245
|
-
}
|
|
246
|
-
throw error
|
|
247
|
-
}
|
|
248
|
-
if (content.includes(WINDOWS_CONDA_ACTIVATE_PINOKIO_MARKER)) {
|
|
249
|
-
return
|
|
250
|
-
}
|
|
251
|
-
const eol = content.includes("\r\n") ? "\r\n" : "\n"
|
|
252
|
-
const originalBlock = windowsCondaActivateOriginalBlock(eol)
|
|
253
|
-
if (!content.includes(originalBlock)) {
|
|
254
|
-
console.warn("Could not patch Conda CMD activation echo leak; unexpected _conda_activate.bat")
|
|
255
|
-
return
|
|
256
|
-
}
|
|
257
|
-
const routineAnchor = `${eol}:: Routine to delete a temp file if CONDA_DEBUG is not set`
|
|
258
|
-
if (!content.includes(routineAnchor)) {
|
|
259
|
-
console.warn("Could not patch Conda CMD activation echo leak; missing _conda_activate.bat routine anchor")
|
|
260
|
-
return
|
|
260
|
+
for (const relativePath of WINDOWS_CONDA_ACTIVATE_RELATIVE_PATHS) {
|
|
261
|
+
const activatePath = this.kernel.bin.path(CONDA_ROOT_DIR, relativePath)
|
|
262
|
+
await fs.promises.mkdir(path.dirname(activatePath), { recursive: true })
|
|
263
|
+
await fs.promises.writeFile(activatePath, WINDOWS_CONDA_ACTIVATE_BAT)
|
|
261
264
|
}
|
|
262
|
-
const patched = content
|
|
263
|
-
.replace(originalBlock, windowsCondaActivatePatchedBlock(eol))
|
|
264
|
-
.replace(
|
|
265
|
-
routineAnchor,
|
|
266
|
-
`${eol}${windowsCondaActivatePatchRoutines(eol)}:: Routine to delete a temp file if CONDA_DEBUG is not set`
|
|
267
|
-
)
|
|
268
|
-
await fs.promises.writeFile(activatePath, patched)
|
|
269
265
|
}
|
|
270
266
|
async init() {
|
|
271
267
|
if (this.kernel.homedir) {
|
|
@@ -289,7 +285,7 @@ report_errors: false`)
|
|
|
289
285
|
await this.ensureCompatibilityAlias()
|
|
290
286
|
}
|
|
291
287
|
await this.ensureWindowsOpenSslHooks()
|
|
292
|
-
await this.
|
|
288
|
+
await this.ensureWindowsCondaActivateBat()
|
|
293
289
|
}
|
|
294
290
|
}
|
|
295
291
|
async check() {
|
|
@@ -438,7 +434,7 @@ report_errors: false`)
|
|
|
438
434
|
)
|
|
439
435
|
}
|
|
440
436
|
await this.ensureWindowsOpenSslHooks()
|
|
441
|
-
await this.
|
|
437
|
+
await this.ensureWindowsCondaActivateBat()
|
|
442
438
|
await this.ensureCompatibilityAlias()
|
|
443
439
|
ondata({ raw: `Install finished\r\n` })
|
|
444
440
|
await this.kernel.bin.rm(installer, ondata)
|
package/package.json
CHANGED
package/test/conda-bin.test.js
CHANGED
|
@@ -125,56 +125,22 @@ const EXPECTED_WINDOWS_OPENSSL_HOOKS = {
|
|
|
125
125
|
].join('\n'),
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
const
|
|
129
|
-
'bin',
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
128
|
+
const WINDOWS_CONDA_ACTIVATE_PATHS = [
|
|
129
|
+
path.join('bin', 'miniforge', 'condabin', '_conda_activate.bat'),
|
|
130
|
+
path.join(
|
|
131
|
+
'bin',
|
|
132
|
+
'miniforge',
|
|
133
|
+
'Lib',
|
|
134
|
+
'site-packages',
|
|
135
|
+
'conda',
|
|
136
|
+
'shell',
|
|
137
|
+
'condabin',
|
|
138
|
+
'_conda_activate.bat'
|
|
139
|
+
),
|
|
140
|
+
]
|
|
141
|
+
const WINDOWS_CONDA_ACTIVATE_LEAK_BLOCK = [
|
|
139
142
|
' ) ELSE ENDLOCAL & (',
|
|
140
143
|
' FOR /F "tokens=1,* delims==" %%A IN (%%T) DO (',
|
|
141
|
-
' :: A, B = "key", "value"',
|
|
142
|
-
' IF "%CONDA_DEBUG%" == "1" ECHO DEBUG: "%%A=%%B">&2',
|
|
143
|
-
' IF "%%A"=="_CONDA_SCRIPT" (',
|
|
144
|
-
' :: Script execution, fast exit if activation scripts fail',
|
|
145
|
-
' CALL "%%B" || (',
|
|
146
|
-
' ECHO ERROR: Activation script "%%B" failed with code %ERRORLEVEL%.>&2',
|
|
147
|
-
' CALL :DELETE "%%T"',
|
|
148
|
-
' CALL :DELETE "%__conda_tmp%"',
|
|
149
|
-
' EXIT /B 4',
|
|
150
|
-
' )',
|
|
151
|
-
' ) ELSE IF "%%B"=="" (',
|
|
152
|
-
' :: Unset variable',
|
|
153
|
-
' SET "%%A="',
|
|
154
|
-
' ) ELSE (',
|
|
155
|
-
' :: Set variable',
|
|
156
|
-
' SET "%%A=%%B"',
|
|
157
|
-
' )',
|
|
158
|
-
' )',
|
|
159
|
-
' :: Clean up',
|
|
160
|
-
' CALL :DELETE "%%T"',
|
|
161
|
-
' CALL :DELETE "%__conda_tmp%"',
|
|
162
|
-
' EXIT /B 0',
|
|
163
|
-
' )',
|
|
164
|
-
].join('\r\n')
|
|
165
|
-
const WINDOWS_CONDA_ACTIVATE_SCRIPT = [
|
|
166
|
-
'@ECHO OFF',
|
|
167
|
-
'SETLOCAL',
|
|
168
|
-
'FOR /F "delims=" %%T IN (%__conda_tmp%) DO (',
|
|
169
|
-
' IF NOT EXIST "%%T" (',
|
|
170
|
-
' ENDLOCAL & EXIT /B 3',
|
|
171
|
-
WINDOWS_CONDA_ACTIVATE_ORIGINAL_BLOCK,
|
|
172
|
-
')',
|
|
173
|
-
'',
|
|
174
|
-
':: Routine to delete a temp file if CONDA_DEBUG is not set',
|
|
175
|
-
':DELETE',
|
|
176
|
-
'GOTO :EOF',
|
|
177
|
-
'',
|
|
178
144
|
].join('\r\n')
|
|
179
145
|
|
|
180
146
|
async function seedWindowsOpenSslHooks(root, condaRootName) {
|
|
@@ -195,11 +161,13 @@ async function seedWindowsOpenSslHooks(root, condaRootName) {
|
|
|
195
161
|
}
|
|
196
162
|
}
|
|
197
163
|
|
|
198
|
-
async function
|
|
199
|
-
const
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
164
|
+
async function seedWindowsCondaActivateScripts(root, content = 'corrupted helper\r\n') {
|
|
165
|
+
const activatePaths = WINDOWS_CONDA_ACTIVATE_PATHS.map((activatePath) => path.join(root, activatePath))
|
|
166
|
+
for (const activatePath of activatePaths) {
|
|
167
|
+
await fs.mkdir(path.dirname(activatePath), { recursive: true })
|
|
168
|
+
await fs.writeFile(activatePath, content)
|
|
169
|
+
}
|
|
170
|
+
return activatePaths
|
|
203
171
|
}
|
|
204
172
|
|
|
205
173
|
async function assertWindowsOpenSslHooksPatched(root, condaRootName) {
|
|
@@ -262,49 +230,22 @@ test('Conda init patches Windows OpenSSL hooks for legacy Miniconda roots', asyn
|
|
|
262
230
|
await assertWindowsOpenSslHooksPatched(root, 'miniconda')
|
|
263
231
|
})
|
|
264
232
|
|
|
265
|
-
test('Conda init
|
|
266
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-cmd-activate-
|
|
267
|
-
await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
|
|
268
|
-
const activatePath = await seedWindowsCondaActivateScript(root)
|
|
269
|
-
const conda = createConda(createKernel(root))
|
|
270
|
-
|
|
271
|
-
await conda.init()
|
|
272
|
-
const patched = await fs.readFile(activatePath, 'utf8')
|
|
273
|
-
await conda.init()
|
|
274
|
-
|
|
275
|
-
assert.equal(await fs.readFile(activatePath, 'utf8'), patched)
|
|
276
|
-
assert.equal(patched.includes(WINDOWS_CONDA_ACTIVATE_ORIGINAL_BLOCK), false)
|
|
277
|
-
assert.match(patched, /ENDLOCAL & @CALL :PINOKIO_APPLY_CONDA_ENV "%%T" "%__conda_tmp%" & @GOTO :EOF/)
|
|
278
|
-
assert.match(patched, /:PINOKIO_APPLY_CONDA_ENV/)
|
|
279
|
-
assert.match(patched, /@CALL "%%B" \|\| \(/)
|
|
280
|
-
assert.match(patched, /:: Routine to delete a temp file if CONDA_DEBUG is not set/)
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
test('Conda init leaves unexpected Windows CMD activation script unchanged', async () => {
|
|
284
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-cmd-activate-unexpected-'))
|
|
233
|
+
test('Conda init replaces Windows CMD activation helper files', async () => {
|
|
234
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-cmd-activate-replace-'))
|
|
285
235
|
await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
|
|
286
|
-
const
|
|
287
|
-
const activatePath = await seedWindowsCondaActivateScript(root, unexpected)
|
|
236
|
+
const activatePaths = await seedWindowsCondaActivateScripts(root)
|
|
288
237
|
const conda = createConda(createKernel(root))
|
|
289
238
|
|
|
290
239
|
await conda.init()
|
|
291
|
-
|
|
292
|
-
assert.equal(await fs.readFile(activatePath, 'utf8'), unexpected)
|
|
293
|
-
})
|
|
294
|
-
|
|
295
|
-
test('Conda init leaves Windows CMD activation script unchanged when patch anchor is missing', async () => {
|
|
296
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-cmd-activate-missing-anchor-'))
|
|
297
|
-
await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
|
|
298
|
-
const missingAnchor = WINDOWS_CONDA_ACTIVATE_SCRIPT.replace(
|
|
299
|
-
'\r\n:: Routine to delete a temp file if CONDA_DEBUG is not set',
|
|
300
|
-
'\r\n:: unexpected routine header'
|
|
301
|
-
)
|
|
302
|
-
const activatePath = await seedWindowsCondaActivateScript(root, missingAnchor)
|
|
303
|
-
const conda = createConda(createKernel(root))
|
|
304
|
-
|
|
305
240
|
await conda.init()
|
|
306
241
|
|
|
307
|
-
|
|
242
|
+
const contents = await Promise.all(activatePaths.map((activatePath) => fs.readFile(activatePath, 'utf8')))
|
|
243
|
+
assert.equal(contents[0], contents[1])
|
|
244
|
+
assert.equal(contents[0].includes(WINDOWS_CONDA_ACTIVATE_LEAK_BLOCK), false)
|
|
245
|
+
assert.match(contents[0], /ENDLOCAL & @CALL :PINOKIO_APPLY_CONDA_ENV "%%T" "%__conda_tmp%" & @GOTO :EOF/)
|
|
246
|
+
assert.match(contents[0], /:PINOKIO_APPLY_CONDA_ENV\r\n@ECHO OFF/)
|
|
247
|
+
assert.match(contents[0], /@CALL "%%B" \|\| \(/)
|
|
248
|
+
assert.match(contents[0], /@ECHO ON\r\n@EXIT \/B 0/)
|
|
308
249
|
})
|
|
309
250
|
|
|
310
251
|
test('Conda pins Python 3.10.20 consistently across platforms', async () => {
|
|
@@ -349,7 +290,6 @@ test('Conda install keeps the Windows Python 3.10.20 SSL-fixed build pin', async
|
|
|
349
290
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-python-pin-win32-'))
|
|
350
291
|
const kernel = createKernel(root, 'win32')
|
|
351
292
|
const calls = []
|
|
352
|
-
let activatePath
|
|
353
293
|
|
|
354
294
|
kernel.bin.mods = []
|
|
355
295
|
kernel.bin.download = async () => {}
|
|
@@ -360,7 +300,6 @@ test('Conda install keeps the Windows Python 3.10.20 SSL-fixed build pin', async
|
|
|
360
300
|
const miniforge = path.join(root, 'bin', 'miniforge')
|
|
361
301
|
await fs.mkdir(path.join(miniforge, 'conda-meta'), { recursive: true })
|
|
362
302
|
await fs.writeFile(path.join(miniforge, 'python.exe'), 'fake python\n')
|
|
363
|
-
activatePath = await seedWindowsCondaActivateScript(root)
|
|
364
303
|
}
|
|
365
304
|
}
|
|
366
305
|
|
|
@@ -373,7 +312,9 @@ test('Conda install keeps the Windows Python 3.10.20 SSL-fixed build pin', async
|
|
|
373
312
|
condaInstall.message[1],
|
|
374
313
|
'conda install -y --override-channels -c conda-forge "python=3.10.20=*_1_cpython" "conda-libmamba-solver>=25.4.0"'
|
|
375
314
|
)
|
|
376
|
-
|
|
315
|
+
for (const activatePath of WINDOWS_CONDA_ACTIVATE_PATHS.map((activatePath) => path.join(root, activatePath))) {
|
|
316
|
+
assert.match(await fs.readFile(activatePath, 'utf8'), /:PINOKIO_APPLY_CONDA_ENV/)
|
|
317
|
+
}
|
|
377
318
|
})
|
|
378
319
|
|
|
379
320
|
test('Conda install replaces legacy miniconda with a compatibility alias to miniforge', async () => {
|