pinokiod 7.5.35 → 7.5.37
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 +0 -126
- package/kernel/shell.js +44 -1
- package/package.json +1 -1
- package/test/conda-bin.test.js +0 -139
- package/test/shell-conda-runtime-guard.test.js +31 -0
package/kernel/bin/conda.js
CHANGED
|
@@ -69,79 +69,6 @@ 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 WINDOWS_CONDA_ACTIVATE_RELATIVE_PATH = path.join(
|
|
73
|
-
"Lib",
|
|
74
|
-
"site-packages",
|
|
75
|
-
"conda",
|
|
76
|
-
"shell",
|
|
77
|
-
"condabin",
|
|
78
|
-
"_conda_activate.bat"
|
|
79
|
-
)
|
|
80
|
-
const WINDOWS_CONDA_ACTIVATE_PINOKIO_MARKER = ":PINOKIO_APPLY_CONDA_ENV"
|
|
81
|
-
|
|
82
|
-
function windowsCondaActivateOriginalBlock(eol) {
|
|
83
|
-
return [
|
|
84
|
-
" ) ELSE ENDLOCAL & (",
|
|
85
|
-
' FOR /F "tokens=1,* delims==" %%A IN (%%T) DO (',
|
|
86
|
-
' :: A, B = "key", "value"',
|
|
87
|
-
' IF "%CONDA_DEBUG%" == "1" ECHO DEBUG: "%%A=%%B">&2',
|
|
88
|
-
' IF "%%A"=="_CONDA_SCRIPT" (',
|
|
89
|
-
" :: Script execution, fast exit if activation scripts fail",
|
|
90
|
-
' CALL "%%B" || (',
|
|
91
|
-
' ECHO ERROR: Activation script "%%B" failed with code %ERRORLEVEL%.>&2',
|
|
92
|
-
' CALL :DELETE "%%T"',
|
|
93
|
-
' CALL :DELETE "%__conda_tmp%"',
|
|
94
|
-
" EXIT /B 4",
|
|
95
|
-
" )",
|
|
96
|
-
' ) ELSE IF "%%B"=="" (',
|
|
97
|
-
" :: Unset variable",
|
|
98
|
-
' SET "%%A="',
|
|
99
|
-
" ) ELSE (",
|
|
100
|
-
" :: Set variable",
|
|
101
|
-
' SET "%%A=%%B"',
|
|
102
|
-
" )",
|
|
103
|
-
" )",
|
|
104
|
-
" :: Clean up",
|
|
105
|
-
' CALL :DELETE "%%T"',
|
|
106
|
-
' CALL :DELETE "%__conda_tmp%"',
|
|
107
|
-
" EXIT /B 0",
|
|
108
|
-
" )",
|
|
109
|
-
].join(eol)
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function windowsCondaActivatePatchedBlock(eol) {
|
|
113
|
-
return [
|
|
114
|
-
' ) ELSE ENDLOCAL & @CALL :PINOKIO_APPLY_CONDA_ENV "%%T" "%__conda_tmp%" & @GOTO :EOF',
|
|
115
|
-
].join(eol)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function windowsCondaActivatePatchRoutines(eol) {
|
|
119
|
-
return [
|
|
120
|
-
":PINOKIO_APPLY_CONDA_ENV",
|
|
121
|
-
"@ECHO OFF",
|
|
122
|
-
'@FOR /F "tokens=1,* delims==" %%A IN (%~1) DO (',
|
|
123
|
-
'@IF "%CONDA_DEBUG%" == "1" ECHO DEBUG: "%%A=%%B">&2',
|
|
124
|
-
'@IF "%%A"=="_CONDA_SCRIPT" (',
|
|
125
|
-
'@CALL "%%B" || (',
|
|
126
|
-
'@ECHO ERROR: Activation script "%%B" failed with code %ERRORLEVEL%.>&2',
|
|
127
|
-
'@CALL :DELETE "%~1"',
|
|
128
|
-
'@CALL :DELETE "%~2"',
|
|
129
|
-
"@ECHO ON",
|
|
130
|
-
"@EXIT /B 4",
|
|
131
|
-
")",
|
|
132
|
-
') ELSE IF "%%B"=="" (',
|
|
133
|
-
'@SET "%%A="',
|
|
134
|
-
") ELSE (",
|
|
135
|
-
'@SET "%%A=%%B"',
|
|
136
|
-
")",
|
|
137
|
-
")",
|
|
138
|
-
'@CALL :DELETE "%~1"',
|
|
139
|
-
'@CALL :DELETE "%~2"',
|
|
140
|
-
"@ECHO ON",
|
|
141
|
-
"@EXIT /B 0",
|
|
142
|
-
"",
|
|
143
|
-
].join(eol)
|
|
144
|
-
}
|
|
145
72
|
|
|
146
73
|
class Conda {
|
|
147
74
|
description = "Pinokio uses Conda to install various useful programs in an isolated manner."
|
|
@@ -234,57 +161,6 @@ class Conda {
|
|
|
234
161
|
}
|
|
235
162
|
}
|
|
236
163
|
}
|
|
237
|
-
async ensureWindowsCondaActivateEchoPatch() {
|
|
238
|
-
if (this.kernel.platform !== "win32" || !(await this.hasCondaMeta())) {
|
|
239
|
-
return
|
|
240
|
-
}
|
|
241
|
-
const activatePath = this.kernel.bin.path(CONDA_ROOT_DIR, WINDOWS_CONDA_ACTIVATE_RELATIVE_PATH)
|
|
242
|
-
let content
|
|
243
|
-
try {
|
|
244
|
-
content = await fs.promises.readFile(activatePath, "utf8")
|
|
245
|
-
} catch (error) {
|
|
246
|
-
if (error && error.code === "ENOENT") {
|
|
247
|
-
return
|
|
248
|
-
}
|
|
249
|
-
throw error
|
|
250
|
-
}
|
|
251
|
-
const eol = content.includes("\r\n") ? "\r\n" : "\n"
|
|
252
|
-
const routineAnchor = `${eol}:: Routine to delete a temp file if CONDA_DEBUG is not set`
|
|
253
|
-
if (!content.includes(routineAnchor)) {
|
|
254
|
-
console.warn("Could not patch Conda CMD activation echo leak; missing _conda_activate.bat routine anchor")
|
|
255
|
-
return
|
|
256
|
-
}
|
|
257
|
-
if (content.includes(WINDOWS_CONDA_ACTIVATE_PINOKIO_MARKER)) {
|
|
258
|
-
if (content.includes(`${WINDOWS_CONDA_ACTIVATE_PINOKIO_MARKER}${eol}@ECHO OFF`)) {
|
|
259
|
-
return
|
|
260
|
-
}
|
|
261
|
-
const routineStart = content.indexOf(WINDOWS_CONDA_ACTIVATE_PINOKIO_MARKER)
|
|
262
|
-
const routineAnchorIndex = content.indexOf(routineAnchor, routineStart)
|
|
263
|
-
if (routineAnchorIndex < 0) {
|
|
264
|
-
console.warn("Could not update Conda CMD activation echo patch; missing _conda_activate.bat routine anchor")
|
|
265
|
-
return
|
|
266
|
-
}
|
|
267
|
-
const patched = [
|
|
268
|
-
content.slice(0, routineStart),
|
|
269
|
-
windowsCondaActivatePatchRoutines(eol),
|
|
270
|
-
content.slice(routineAnchorIndex + eol.length),
|
|
271
|
-
].join("")
|
|
272
|
-
await fs.promises.writeFile(activatePath, patched)
|
|
273
|
-
return
|
|
274
|
-
}
|
|
275
|
-
const originalBlock = windowsCondaActivateOriginalBlock(eol)
|
|
276
|
-
if (!content.includes(originalBlock)) {
|
|
277
|
-
console.warn("Could not patch Conda CMD activation echo leak; unexpected _conda_activate.bat")
|
|
278
|
-
return
|
|
279
|
-
}
|
|
280
|
-
const patched = content
|
|
281
|
-
.replace(originalBlock, windowsCondaActivatePatchedBlock(eol))
|
|
282
|
-
.replace(
|
|
283
|
-
routineAnchor,
|
|
284
|
-
`${eol}${windowsCondaActivatePatchRoutines(eol)}:: Routine to delete a temp file if CONDA_DEBUG is not set`
|
|
285
|
-
)
|
|
286
|
-
await fs.promises.writeFile(activatePath, patched)
|
|
287
|
-
}
|
|
288
164
|
async init() {
|
|
289
165
|
if (this.kernel.homedir) {
|
|
290
166
|
console.log("condarc init")
|
|
@@ -307,7 +183,6 @@ report_errors: false`)
|
|
|
307
183
|
await this.ensureCompatibilityAlias()
|
|
308
184
|
}
|
|
309
185
|
await this.ensureWindowsOpenSslHooks()
|
|
310
|
-
await this.ensureWindowsCondaActivateEchoPatch()
|
|
311
186
|
}
|
|
312
187
|
}
|
|
313
188
|
async check() {
|
|
@@ -456,7 +331,6 @@ report_errors: false`)
|
|
|
456
331
|
)
|
|
457
332
|
}
|
|
458
333
|
await this.ensureWindowsOpenSslHooks()
|
|
459
|
-
await this.ensureWindowsCondaActivateEchoPatch()
|
|
460
334
|
await this.ensureCompatibilityAlias()
|
|
461
335
|
ondata({ raw: `Install finished\r\n` })
|
|
462
336
|
await this.kernel.bin.rm(installer, ondata)
|
package/kernel/shell.js
CHANGED
|
@@ -23,6 +23,7 @@ const ShellRunTemplate = require('./api/shell_run_template')
|
|
|
23
23
|
const { PYTHON_INSTALL_SPEC } = require('./bin/conda-pins')
|
|
24
24
|
const CondaRuntimeGuard = require('./shell_conda_runtime_guard')
|
|
25
25
|
const home = os.homedir()
|
|
26
|
+
const WINDOWS_CMD_CONDA_COMMAND_PATTERN = /(?:^|[&|()]\s*)@?\s*(?:call\s+)?(?:"[^"]*[\\/]conda(?:\.bat|\.exe)?"|(?:[a-z]:)?[^&|()\s"]*[\\/]conda(?:\.bat|\.exe)?|conda(?:\.bat|\.exe)?)\s+/i
|
|
26
27
|
|
|
27
28
|
function normalizeComparablePath(filePath, platform) {
|
|
28
29
|
const normalized = path.normalize(filePath)
|
|
@@ -335,6 +336,33 @@ class Shell {
|
|
|
335
336
|
const name = (shellName || '').toLowerCase()
|
|
336
337
|
return name.includes('powershell') || name.includes('pwsh')
|
|
337
338
|
}
|
|
339
|
+
hasCondaCommand(message) {
|
|
340
|
+
if (Array.isArray(message)) {
|
|
341
|
+
return message.some((item) => this.hasCondaCommand(item))
|
|
342
|
+
}
|
|
343
|
+
if (message && message.constructor === Object) {
|
|
344
|
+
return this.hasCondaCommand(this.buildStructuredMessage(message))
|
|
345
|
+
}
|
|
346
|
+
return typeof message === "string" && WINDOWS_CMD_CONDA_COMMAND_PATTERN.test(message)
|
|
347
|
+
}
|
|
348
|
+
shouldSuppressCmdEchoForConda(params) {
|
|
349
|
+
return this.platform === "win32" &&
|
|
350
|
+
this.isCmdShell() &&
|
|
351
|
+
!(params && params.input) &&
|
|
352
|
+
this.hasCondaCommand(params && params.message)
|
|
353
|
+
}
|
|
354
|
+
buildCmdEchoSuppressedCommand(command) {
|
|
355
|
+
return `@echo off\r\n${command}\r\n@echo on`
|
|
356
|
+
}
|
|
357
|
+
prepareCommandExecution(params, command) {
|
|
358
|
+
if (!this.shouldSuppressCmdEchoForConda(params)) {
|
|
359
|
+
return { command }
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
command: this.buildCmdEchoSuppressedCommand(command),
|
|
363
|
+
preview: command,
|
|
364
|
+
}
|
|
365
|
+
}
|
|
338
366
|
isUnresolvedTemplate(value) {
|
|
339
367
|
return typeof value === "string" && /^\{\{[\s\S]*\}\}$/.test(value)
|
|
340
368
|
}
|
|
@@ -413,6 +441,9 @@ class Shell {
|
|
|
413
441
|
this.decsyncBuffer = ''
|
|
414
442
|
this.stateSync.reset()
|
|
415
443
|
this.envArgsPreviewed = false
|
|
444
|
+
this.commandEchoPreview = null
|
|
445
|
+
this.commandEchoPreviewed = false
|
|
446
|
+
this.exec_cmd = null
|
|
416
447
|
|
|
417
448
|
/*
|
|
418
449
|
params := {
|
|
@@ -1399,8 +1430,16 @@ class Shell {
|
|
|
1399
1430
|
async exec(params) {
|
|
1400
1431
|
this.parser = new ShellParser()
|
|
1401
1432
|
this.emitEnvArgsPreview(params)
|
|
1433
|
+
const originalParams = {
|
|
1434
|
+
input: params && params.input,
|
|
1435
|
+
message: params && params.message,
|
|
1436
|
+
}
|
|
1402
1437
|
params = await this.activate(params)
|
|
1403
1438
|
this.cmd = this.build(params)
|
|
1439
|
+
const preparedCommand = this.prepareCommandExecution(originalParams, this.cmd)
|
|
1440
|
+
this.exec_cmd = preparedCommand.command
|
|
1441
|
+
this.commandEchoPreview = preparedCommand.preview || null
|
|
1442
|
+
this.commandEchoPreviewed = false
|
|
1404
1443
|
let res = await new Promise((resolve, reject) => {
|
|
1405
1444
|
this.resolve = resolve
|
|
1406
1445
|
this.reject = reject
|
|
@@ -1853,7 +1892,11 @@ ${cleaned}
|
|
|
1853
1892
|
}
|
|
1854
1893
|
if (this.ptyProcess) {
|
|
1855
1894
|
this.stateSync.noteInput()
|
|
1856
|
-
|
|
1895
|
+
if (this.commandEchoPreview && !this.commandEchoPreviewed) {
|
|
1896
|
+
this.commandEchoPreviewed = true
|
|
1897
|
+
this.queue.push(`${this.commandEchoPreview}${this.EOL}`)
|
|
1898
|
+
}
|
|
1899
|
+
this.ptyProcess.write(`${this.exec_cmd || this.cmd}${this.EOL}`)
|
|
1857
1900
|
// setTimeout(() => {
|
|
1858
1901
|
// this.ptyProcess.write('\x1B[?2004h');
|
|
1859
1902
|
// }, 500)
|
package/package.json
CHANGED
package/test/conda-bin.test.js
CHANGED
|
@@ -125,58 +125,6 @@ const EXPECTED_WINDOWS_OPENSSL_HOOKS = {
|
|
|
125
125
|
].join('\n'),
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
const WINDOWS_CONDA_ACTIVATE_PATH = path.join(
|
|
129
|
-
'bin',
|
|
130
|
-
'miniforge',
|
|
131
|
-
'Lib',
|
|
132
|
-
'site-packages',
|
|
133
|
-
'conda',
|
|
134
|
-
'shell',
|
|
135
|
-
'condabin',
|
|
136
|
-
'_conda_activate.bat'
|
|
137
|
-
)
|
|
138
|
-
const WINDOWS_CONDA_ACTIVATE_ORIGINAL_BLOCK = [
|
|
139
|
-
' ) ELSE ENDLOCAL & (',
|
|
140
|
-
' 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
|
-
].join('\r\n')
|
|
179
|
-
|
|
180
128
|
async function seedWindowsOpenSslHooks(root, condaRootName) {
|
|
181
129
|
const condaHookRoot = path.join(root, 'bin', condaRootName, 'etc', 'conda')
|
|
182
130
|
for (const hookRelativePath of Object.keys(EXPECTED_WINDOWS_OPENSSL_HOOKS)) {
|
|
@@ -195,13 +143,6 @@ async function seedWindowsOpenSslHooks(root, condaRootName) {
|
|
|
195
143
|
}
|
|
196
144
|
}
|
|
197
145
|
|
|
198
|
-
async function seedWindowsCondaActivateScript(root, content = WINDOWS_CONDA_ACTIVATE_SCRIPT) {
|
|
199
|
-
const activatePath = path.join(root, WINDOWS_CONDA_ACTIVATE_PATH)
|
|
200
|
-
await fs.mkdir(path.dirname(activatePath), { recursive: true })
|
|
201
|
-
await fs.writeFile(activatePath, content)
|
|
202
|
-
return activatePath
|
|
203
|
-
}
|
|
204
|
-
|
|
205
146
|
async function assertWindowsOpenSslHooksPatched(root, condaRootName) {
|
|
206
147
|
const condaHookRoot = path.join(root, 'bin', condaRootName, 'etc', 'conda')
|
|
207
148
|
for (const [hookRelativePath, expectedContent] of Object.entries(EXPECTED_WINDOWS_OPENSSL_HOOKS)) {
|
|
@@ -262,83 +203,6 @@ test('Conda init patches Windows OpenSSL hooks for legacy Miniconda roots', asyn
|
|
|
262
203
|
await assertWindowsOpenSslHooksPatched(root, 'miniconda')
|
|
263
204
|
})
|
|
264
205
|
|
|
265
|
-
test('Conda init patches Windows CMD activation echo leak idempotently', async () => {
|
|
266
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-cmd-activate-patch-'))
|
|
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\r\n@ECHO OFF/)
|
|
279
|
-
assert.match(patched, /@CALL "%%B" \|\| \(/)
|
|
280
|
-
assert.match(patched, /@ECHO ON\r\n@EXIT \/B 0/)
|
|
281
|
-
assert.match(patched, /:: Routine to delete a temp file if CONDA_DEBUG is not set/)
|
|
282
|
-
})
|
|
283
|
-
|
|
284
|
-
test('Conda init updates the earlier Windows CMD activation echo patch', async () => {
|
|
285
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-cmd-activate-update-patch-'))
|
|
286
|
-
await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
|
|
287
|
-
const oldPatch = WINDOWS_CONDA_ACTIVATE_SCRIPT
|
|
288
|
-
.replace(
|
|
289
|
-
WINDOWS_CONDA_ACTIVATE_ORIGINAL_BLOCK,
|
|
290
|
-
' ) ELSE ENDLOCAL & @CALL :PINOKIO_APPLY_CONDA_ENV "%%T" "%__conda_tmp%" & @GOTO :EOF'
|
|
291
|
-
)
|
|
292
|
-
.replace(
|
|
293
|
-
'\r\n:: Routine to delete a temp file if CONDA_DEBUG is not set',
|
|
294
|
-
[
|
|
295
|
-
'\r\n:PINOKIO_APPLY_CONDA_ENV',
|
|
296
|
-
'@FOR /F "tokens=1,* delims==" %%A IN (%~1) DO (',
|
|
297
|
-
'@IF "%CONDA_DEBUG%" == "1" ECHO DEBUG: "%%A=%%B">&2',
|
|
298
|
-
')',
|
|
299
|
-
'@CALL :DELETE "%~1"',
|
|
300
|
-
'@CALL :DELETE "%~2"',
|
|
301
|
-
'@EXIT /B 0',
|
|
302
|
-
':: Routine to delete a temp file if CONDA_DEBUG is not set',
|
|
303
|
-
].join('\r\n')
|
|
304
|
-
)
|
|
305
|
-
const activatePath = await seedWindowsCondaActivateScript(root, oldPatch)
|
|
306
|
-
const conda = createConda(createKernel(root))
|
|
307
|
-
|
|
308
|
-
await conda.init()
|
|
309
|
-
|
|
310
|
-
const patched = await fs.readFile(activatePath, 'utf8')
|
|
311
|
-
assert.match(patched, /:PINOKIO_APPLY_CONDA_ENV\r\n@ECHO OFF/)
|
|
312
|
-
assert.match(patched, /@ECHO ON\r\n@EXIT \/B 0/)
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
test('Conda init leaves unexpected Windows CMD activation script unchanged', async () => {
|
|
316
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-cmd-activate-unexpected-'))
|
|
317
|
-
await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
|
|
318
|
-
const unexpected = '@ECHO OFF\r\nREM unexpected upstream script\r\n'
|
|
319
|
-
const activatePath = await seedWindowsCondaActivateScript(root, unexpected)
|
|
320
|
-
const conda = createConda(createKernel(root))
|
|
321
|
-
|
|
322
|
-
await conda.init()
|
|
323
|
-
|
|
324
|
-
assert.equal(await fs.readFile(activatePath, 'utf8'), unexpected)
|
|
325
|
-
})
|
|
326
|
-
|
|
327
|
-
test('Conda init leaves Windows CMD activation script unchanged when patch anchor is missing', async () => {
|
|
328
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-cmd-activate-missing-anchor-'))
|
|
329
|
-
await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
|
|
330
|
-
const missingAnchor = WINDOWS_CONDA_ACTIVATE_SCRIPT.replace(
|
|
331
|
-
'\r\n:: Routine to delete a temp file if CONDA_DEBUG is not set',
|
|
332
|
-
'\r\n:: unexpected routine header'
|
|
333
|
-
)
|
|
334
|
-
const activatePath = await seedWindowsCondaActivateScript(root, missingAnchor)
|
|
335
|
-
const conda = createConda(createKernel(root))
|
|
336
|
-
|
|
337
|
-
await conda.init()
|
|
338
|
-
|
|
339
|
-
assert.equal(await fs.readFile(activatePath, 'utf8'), missingAnchor)
|
|
340
|
-
})
|
|
341
|
-
|
|
342
206
|
test('Conda pins Python 3.10.20 consistently across platforms', async () => {
|
|
343
207
|
assert.equal(PYTHON_INSTALL_SPEC, 'python=3.10.20')
|
|
344
208
|
assert.equal(WINDOWS_PYTHON_SSL_FIX_SPEC, 'python=3.10.20=*_1_cpython')
|
|
@@ -381,7 +245,6 @@ test('Conda install keeps the Windows Python 3.10.20 SSL-fixed build pin', async
|
|
|
381
245
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-python-pin-win32-'))
|
|
382
246
|
const kernel = createKernel(root, 'win32')
|
|
383
247
|
const calls = []
|
|
384
|
-
let activatePath
|
|
385
248
|
|
|
386
249
|
kernel.bin.mods = []
|
|
387
250
|
kernel.bin.download = async () => {}
|
|
@@ -392,7 +255,6 @@ test('Conda install keeps the Windows Python 3.10.20 SSL-fixed build pin', async
|
|
|
392
255
|
const miniforge = path.join(root, 'bin', 'miniforge')
|
|
393
256
|
await fs.mkdir(path.join(miniforge, 'conda-meta'), { recursive: true })
|
|
394
257
|
await fs.writeFile(path.join(miniforge, 'python.exe'), 'fake python\n')
|
|
395
|
-
activatePath = await seedWindowsCondaActivateScript(root)
|
|
396
258
|
}
|
|
397
259
|
}
|
|
398
260
|
|
|
@@ -405,7 +267,6 @@ test('Conda install keeps the Windows Python 3.10.20 SSL-fixed build pin', async
|
|
|
405
267
|
condaInstall.message[1],
|
|
406
268
|
'conda install -y --override-channels -c conda-forge "python=3.10.20=*_1_cpython" "conda-libmamba-solver>=25.4.0"'
|
|
407
269
|
)
|
|
408
|
-
assert.match(await fs.readFile(activatePath, 'utf8'), /:PINOKIO_APPLY_CONDA_ENV/)
|
|
409
270
|
})
|
|
410
271
|
|
|
411
272
|
test('Conda install replaces legacy miniconda with a compatibility alias to miniforge', async () => {
|
|
@@ -917,6 +917,37 @@ test('internal shell activation inspects only when shell.run guard option is set
|
|
|
917
917
|
assert.equal(events.some((event) => event.type === 'notify'), true)
|
|
918
918
|
})
|
|
919
919
|
|
|
920
|
+
test('Windows cmd suppresses echo only for explicit conda shell.run commands', () => {
|
|
921
|
+
const shell = new Shell({ bracketedPasteSupport: {} })
|
|
922
|
+
shell.platform = 'win32'
|
|
923
|
+
shell.shell = 'cmd.exe'
|
|
924
|
+
const command = 'conda_hook & conda deactivate & conda activate base & conda install -y -c conda-forge ffmpeg'
|
|
925
|
+
|
|
926
|
+
assert.equal(shell.shouldSuppressCmdEchoForConda({
|
|
927
|
+
message: 'conda install -y -c conda-forge ffmpeg',
|
|
928
|
+
}), true)
|
|
929
|
+
assert.equal(shell.shouldSuppressCmdEchoForConda({
|
|
930
|
+
message: 'python main.py',
|
|
931
|
+
}), false)
|
|
932
|
+
assert.equal(shell.shouldSuppressCmdEchoForConda({
|
|
933
|
+
message: 'conda_hook',
|
|
934
|
+
}), false)
|
|
935
|
+
assert.equal(shell.shouldSuppressCmdEchoForConda({
|
|
936
|
+
input: true,
|
|
937
|
+
message: 'conda install -y -c conda-forge ffmpeg',
|
|
938
|
+
}), false)
|
|
939
|
+
|
|
940
|
+
const prepared = shell.prepareCommandExecution({
|
|
941
|
+
message: 'conda install -y -c conda-forge ffmpeg',
|
|
942
|
+
}, command)
|
|
943
|
+
assert.equal(prepared.preview, command)
|
|
944
|
+
assert.equal(prepared.command, `@echo off\r\n${command}\r\n@echo on`)
|
|
945
|
+
|
|
946
|
+
assert.deepEqual(shell.prepareCommandExecution({
|
|
947
|
+
message: 'python main.py',
|
|
948
|
+
}, command), { command })
|
|
949
|
+
})
|
|
950
|
+
|
|
920
951
|
test('rewrite warning is scoped to each user-visible shell flow', async () => {
|
|
921
952
|
CondaRuntimeGuard.resetNoticeSessionsForTest()
|
|
922
953
|
const { context, events, root } = createContext()
|