pinokiod 8.0.2 → 8.0.3
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-pins.js +4 -3
- package/kernel/bin/conda.js +4 -10
- package/kernel/bin/index.js +3 -7
- package/package.json +1 -1
- package/test/conda-bin.test.js +31 -41
package/kernel/bin/conda-pins.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
const semver = require('semver')
|
|
2
2
|
|
|
3
|
-
const CONDA_PIN_VERSION = "26.3
|
|
4
|
-
const CONDA_RUNTIME_MARKER = ".pinokio-runtime-v1"
|
|
3
|
+
const CONDA_PIN_VERSION = "26.5.3"
|
|
5
4
|
const PYTHON_PIN_VERSION = "3.10.20"
|
|
6
5
|
const PYTHON_INSTALL_SPEC = `python=${PYTHON_PIN_VERSION}`
|
|
7
6
|
const WINDOWS_PYTHON_SSL_FIX_SPEC = `${PYTHON_INSTALL_SPEC}=*_1_cpython`
|
|
8
7
|
|
|
8
|
+
const isExpectedCondaPinned = (version) => String(version) === CONDA_PIN_VERSION
|
|
9
|
+
|
|
9
10
|
const condaBuildNumber = (build) => {
|
|
10
11
|
const chunks = String(build || "").split("_").reverse()
|
|
11
12
|
const buildNumber = chunks.find((chunk) => /^\d+$/.test(chunk))
|
|
@@ -29,8 +30,8 @@ const isExpectedPythonPinned = (platform, version, build) => {
|
|
|
29
30
|
|
|
30
31
|
module.exports = {
|
|
31
32
|
CONDA_PIN_VERSION,
|
|
32
|
-
CONDA_RUNTIME_MARKER,
|
|
33
33
|
PYTHON_INSTALL_SPEC,
|
|
34
34
|
WINDOWS_PYTHON_SSL_FIX_SPEC,
|
|
35
|
+
isExpectedCondaPinned,
|
|
35
36
|
isExpectedPythonPinned,
|
|
36
37
|
}
|
package/kernel/bin/conda.js
CHANGED
|
@@ -4,9 +4,9 @@ const semver = require('semver')
|
|
|
4
4
|
const { buildCondaListFromMeta, managedCondaRuns } = require('./conda-meta')
|
|
5
5
|
const {
|
|
6
6
|
CONDA_PIN_VERSION,
|
|
7
|
-
CONDA_RUNTIME_MARKER,
|
|
8
7
|
PYTHON_INSTALL_SPEC,
|
|
9
8
|
WINDOWS_PYTHON_SSL_FIX_SPEC,
|
|
9
|
+
isExpectedCondaPinned,
|
|
10
10
|
isExpectedPythonPinned,
|
|
11
11
|
} = require('./conda-pins')
|
|
12
12
|
|
|
@@ -48,9 +48,6 @@ class Conda {
|
|
|
48
48
|
async hasCondaMeta() {
|
|
49
49
|
return await this.kernel.exists(`bin/${CONDA_ROOT_DIR}/conda-meta`)
|
|
50
50
|
}
|
|
51
|
-
async hasRuntimeMarker() {
|
|
52
|
-
return await this.kernel.exists(`bin/${CONDA_ROOT_DIR}/${CONDA_RUNTIME_MARKER}`)
|
|
53
|
-
}
|
|
54
51
|
env() {
|
|
55
52
|
let base = {
|
|
56
53
|
CONDA_PREFIX: this.kernel.bin.path(CONDA_ROOT_DIR),
|
|
@@ -96,9 +93,6 @@ report_errors: false`)
|
|
|
96
93
|
}
|
|
97
94
|
}
|
|
98
95
|
async check() {
|
|
99
|
-
if (!(await this.hasRuntimeMarker())) {
|
|
100
|
-
return false
|
|
101
|
-
}
|
|
102
96
|
let res = await buildCondaListFromMeta(this.kernel.bin.path(CONDA_ROOT_DIR))
|
|
103
97
|
|
|
104
98
|
let lines = res.response.split(/[\r\n]+/)
|
|
@@ -118,7 +112,7 @@ report_errors: false`)
|
|
|
118
112
|
conda_versions[name] = version
|
|
119
113
|
conda_builds[name] = build
|
|
120
114
|
if (name === "conda") {
|
|
121
|
-
conda_check.conda =
|
|
115
|
+
conda_check.conda = isExpectedCondaPinned(version)
|
|
122
116
|
}
|
|
123
117
|
// check conda-libmamba-solver is up to date
|
|
124
118
|
// sometimes it just fails silently so need to check
|
|
@@ -220,6 +214,7 @@ report_errors: false`)
|
|
|
220
214
|
console.log("Conda dependencies to install", { mods })
|
|
221
215
|
|
|
222
216
|
let condaPackages = [
|
|
217
|
+
`"conda=${CONDA_PIN_VERSION}"`,
|
|
223
218
|
this.kernel.platform === "win32" ? `"${WINDOWS_PYTHON_SSL_FIX_SPEC}"` : `"${PYTHON_INSTALL_SPEC}"`,
|
|
224
219
|
`"conda-libmamba-solver>=25.4.0"`,
|
|
225
220
|
]
|
|
@@ -244,9 +239,8 @@ report_errors: false`)
|
|
|
244
239
|
)
|
|
245
240
|
}
|
|
246
241
|
await this.ensureCompatibilityAlias()
|
|
247
|
-
await this.kernel.bin.rm(installer, ondata)
|
|
248
|
-
await fs.promises.writeFile(this.kernel.bin.path(CONDA_ROOT_DIR, CONDA_RUNTIME_MARKER), "")
|
|
249
242
|
ondata({ raw: `Install finished\r\n` })
|
|
243
|
+
await this.kernel.bin.rm(installer, ondata)
|
|
250
244
|
}
|
|
251
245
|
async removeInstallPath(target) {
|
|
252
246
|
try {
|
package/kernel/bin/index.js
CHANGED
|
@@ -23,7 +23,7 @@ const Cuda = require("./cuda")
|
|
|
23
23
|
const Torch = require("./torch")
|
|
24
24
|
const { buildCondaListFromMeta, managedCondaRuns } = require('./conda-meta')
|
|
25
25
|
const {
|
|
26
|
-
|
|
26
|
+
isExpectedCondaPinned,
|
|
27
27
|
isExpectedPythonPinned,
|
|
28
28
|
} = require('./conda-pins')
|
|
29
29
|
const { glob } = require('glob')
|
|
@@ -350,10 +350,6 @@ class Bin {
|
|
|
350
350
|
let conda_builds = {}
|
|
351
351
|
this.correct_conda = false
|
|
352
352
|
|
|
353
|
-
const runtimeMarkerExists = await fs.promises.access(
|
|
354
|
-
this.kernel.bin.path("miniforge", CONDA_RUNTIME_MARKER)
|
|
355
|
-
).then(() => true).catch(() => false)
|
|
356
|
-
|
|
357
353
|
//////////////////////////////////////////////////////////////////
|
|
358
354
|
// exception handling
|
|
359
355
|
// if importlib_metadata || uvicorn || fastapi exist in the base environment, this.correct_conda = false
|
|
@@ -380,7 +376,7 @@ class Bin {
|
|
|
380
376
|
|
|
381
377
|
let to_reset_exists = false
|
|
382
378
|
|
|
383
|
-
if (
|
|
379
|
+
if (to_reset_exists) {
|
|
384
380
|
this.correct_conda = false
|
|
385
381
|
} else {
|
|
386
382
|
let res = await buildCondaListFromMeta(this.kernel.bin.path("miniforge"))
|
|
@@ -396,7 +392,7 @@ class Bin {
|
|
|
396
392
|
conda_versions[name] = version
|
|
397
393
|
conda_builds[name] = build
|
|
398
394
|
if (name === "conda") {
|
|
399
|
-
conda_check.conda =
|
|
395
|
+
conda_check.conda = isExpectedCondaPinned(version)
|
|
400
396
|
}
|
|
401
397
|
if (name === "conda-libmamba-solver") {
|
|
402
398
|
let coerced = semver.coerce(version)
|
package/package.json
CHANGED
package/test/conda-bin.test.js
CHANGED
|
@@ -9,9 +9,9 @@ const Bin = require('../kernel/bin')
|
|
|
9
9
|
const Conda = require('../kernel/bin/conda')
|
|
10
10
|
const {
|
|
11
11
|
CONDA_PIN_VERSION,
|
|
12
|
-
CONDA_RUNTIME_MARKER,
|
|
13
12
|
PYTHON_INSTALL_SPEC,
|
|
14
13
|
WINDOWS_PYTHON_SSL_FIX_SPEC,
|
|
14
|
+
isExpectedCondaPinned,
|
|
15
15
|
isExpectedPythonPinned,
|
|
16
16
|
} = require('../kernel/bin/conda-pins')
|
|
17
17
|
|
|
@@ -44,19 +44,12 @@ async function writeCondaMeta(root, name, version, build = 'py_0') {
|
|
|
44
44
|
)
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
async function writeHealthyCondaMeta(root, platform = 'win32') {
|
|
48
|
-
await writeCondaMeta(root, 'conda',
|
|
47
|
+
async function writeHealthyCondaMeta(root, platform = 'win32', condaVersion = CONDA_PIN_VERSION) {
|
|
48
|
+
await writeCondaMeta(root, 'conda', condaVersion, 'py310')
|
|
49
49
|
await writeCondaMeta(root, 'conda-libmamba-solver', '25.4.0', 'pyhd3eb1b0_0')
|
|
50
50
|
await writeCondaMeta(root, 'python', '3.10.20', platform === 'win32' ? 'h4de0772_1_cpython' : 'cpython')
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
async function writeRuntimeMarker(root) {
|
|
54
|
-
const marker = path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)
|
|
55
|
-
await fs.mkdir(path.dirname(marker), { recursive: true })
|
|
56
|
-
await fs.writeFile(marker, '')
|
|
57
|
-
return marker
|
|
58
|
-
}
|
|
59
|
-
|
|
60
53
|
async function writeFakeManagedConda(root, platform = 'win32') {
|
|
61
54
|
const condaPath = platform === 'win32'
|
|
62
55
|
? path.join(root, 'bin', 'miniforge', 'Scripts', 'conda.exe')
|
|
@@ -123,11 +116,13 @@ test('Conda uses Miniforge assets and writes conda-forge-only config', async ()
|
|
|
123
116
|
})
|
|
124
117
|
|
|
125
118
|
test('Conda pins the managed Conda and Python versions consistently', async () => {
|
|
126
|
-
assert.equal(CONDA_PIN_VERSION, '26.3
|
|
127
|
-
assert.equal(CONDA_RUNTIME_MARKER, '.pinokio-runtime-v1')
|
|
119
|
+
assert.equal(CONDA_PIN_VERSION, '26.5.3')
|
|
128
120
|
assert.equal(PYTHON_INSTALL_SPEC, 'python=3.10.20')
|
|
129
121
|
assert.equal(WINDOWS_PYTHON_SSL_FIX_SPEC, 'python=3.10.20=*_1_cpython')
|
|
130
122
|
|
|
123
|
+
assert.equal(isExpectedCondaPinned('26.5.3'), true)
|
|
124
|
+
assert.equal(isExpectedCondaPinned('26.3.2'), false)
|
|
125
|
+
|
|
131
126
|
assert.equal(isExpectedPythonPinned('darwin', '3.10.20', 'cpython'), true)
|
|
132
127
|
assert.equal(isExpectedPythonPinned('linux', '3.10.20', 'cpython'), true)
|
|
133
128
|
assert.equal(isExpectedPythonPinned('darwin', '3.10.21', 'cpython'), false)
|
|
@@ -136,17 +131,16 @@ test('Conda pins the managed Conda and Python versions consistently', async () =
|
|
|
136
131
|
assert.equal(isExpectedPythonPinned('win32', '3.10.20', 'h4de0772_1_cpython'), true)
|
|
137
132
|
})
|
|
138
133
|
|
|
139
|
-
test('Conda init
|
|
140
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-
|
|
134
|
+
test('Conda init writes the current Conda pin into an existing runtime', async () => {
|
|
135
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-pin-init-'))
|
|
141
136
|
await createMiniforge(root)
|
|
142
137
|
await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
|
|
143
138
|
|
|
144
139
|
await createConda(createKernel(root, 'darwin')).init()
|
|
145
140
|
|
|
146
|
-
assert.equal(await pathExists(path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)), false)
|
|
147
141
|
assert.equal(
|
|
148
142
|
await fs.readFile(path.join(root, 'bin', 'miniforge', 'conda-meta', 'pinned'), 'utf8'),
|
|
149
|
-
'conda ==26.3
|
|
143
|
+
'conda ==26.5.3'
|
|
150
144
|
)
|
|
151
145
|
})
|
|
152
146
|
|
|
@@ -200,13 +194,12 @@ test('Conda install requests the Python 3.10.20 pin on macOS/Linux', async () =>
|
|
|
200
194
|
assert.ok(condaInstall)
|
|
201
195
|
assert.equal(
|
|
202
196
|
condaInstall.message[1],
|
|
203
|
-
'conda install -y --override-channels -c conda-forge "python=3.10.20" "conda-libmamba-solver>=25.4.0"'
|
|
197
|
+
'conda install -y --override-channels -c conda-forge "conda=26.5.3" "python=3.10.20" "conda-libmamba-solver>=25.4.0"'
|
|
204
198
|
)
|
|
205
199
|
assert.equal(
|
|
206
200
|
await fs.readFile(path.join(root, 'bin', 'miniforge', 'conda-meta', 'pinned'), 'utf8'),
|
|
207
|
-
'conda ==26.3
|
|
201
|
+
'conda ==26.5.3'
|
|
208
202
|
)
|
|
209
|
-
assert.equal(await pathExists(path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)), true)
|
|
210
203
|
})
|
|
211
204
|
|
|
212
205
|
test('Conda install keeps the Windows Python 3.10.20 SSL-fixed build pin', async () => {
|
|
@@ -233,9 +226,8 @@ test('Conda install keeps the Windows Python 3.10.20 SSL-fixed build pin', async
|
|
|
233
226
|
assert.ok(condaInstall)
|
|
234
227
|
assert.equal(
|
|
235
228
|
condaInstall.message[1],
|
|
236
|
-
'conda install -y --override-channels -c conda-forge "python=3.10.20=*_1_cpython" "conda-libmamba-solver>=25.4.0"'
|
|
229
|
+
'conda install -y --override-channels -c conda-forge "conda=26.5.3" "python=3.10.20=*_1_cpython" "conda-libmamba-solver>=25.4.0"'
|
|
237
230
|
)
|
|
238
|
-
assert.equal(await pathExists(path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)), true)
|
|
239
231
|
})
|
|
240
232
|
|
|
241
233
|
test('Conda install replaces the stale runtime and rebuilds declared Conda modules', async () => {
|
|
@@ -266,9 +258,8 @@ test('Conda install replaces the stale runtime and rebuilds declared Conda modul
|
|
|
266
258
|
assert.ok(condaInstall)
|
|
267
259
|
assert.equal(
|
|
268
260
|
condaInstall.message[1],
|
|
269
|
-
'conda install -y --override-channels -c conda-forge "python=3.10.20" "conda-libmamba-solver>=25.4.0" uv=0.11.23 nodejs=22.21.1 pnpm'
|
|
261
|
+
'conda install -y --override-channels -c conda-forge "conda=26.5.3" "python=3.10.20" "conda-libmamba-solver>=25.4.0" uv=0.11.23 nodejs=22.21.1 pnpm'
|
|
270
262
|
)
|
|
271
|
-
assert.equal(await pathExists(path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)), true)
|
|
272
263
|
})
|
|
273
264
|
|
|
274
265
|
test('Conda install replaces legacy miniconda with a compatibility alias to miniforge', async () => {
|
|
@@ -329,14 +320,13 @@ test('Conda installed stays false when metadata check already marked Conda inval
|
|
|
329
320
|
test('Conda check rejects metadata-only Windows installs', async () => {
|
|
330
321
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-smoke-missing-'))
|
|
331
322
|
await writeHealthyCondaMeta(root, 'win32')
|
|
332
|
-
await writeRuntimeMarker(root)
|
|
333
323
|
|
|
334
324
|
assert.equal(await createConda(createKernel(root, 'win32')).check(), false)
|
|
335
325
|
})
|
|
336
326
|
|
|
337
|
-
test('Conda check rejects
|
|
338
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-
|
|
339
|
-
await writeHealthyCondaMeta(root, 'win32')
|
|
327
|
+
test('Conda check rejects a runnable runtime with the previous Conda version', async () => {
|
|
328
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-version-stale-'))
|
|
329
|
+
await writeHealthyCondaMeta(root, 'win32', '26.3.2')
|
|
340
330
|
await writeFakeManagedConda(root, 'win32')
|
|
341
331
|
|
|
342
332
|
assert.equal(await createConda(createKernel(root, 'win32')).check(), false)
|
|
@@ -346,24 +336,26 @@ test('Conda check accepts a runnable managed Windows conda executable', async ()
|
|
|
346
336
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-smoke-runnable-'))
|
|
347
337
|
await writeHealthyCondaMeta(root, 'win32')
|
|
348
338
|
await writeFakeManagedConda(root, 'win32')
|
|
349
|
-
await writeRuntimeMarker(root)
|
|
350
339
|
|
|
351
340
|
assert.equal(await createConda(createKernel(root, 'win32')).check(), true)
|
|
352
341
|
})
|
|
353
342
|
|
|
354
|
-
test('Bin readiness rejects
|
|
355
|
-
const
|
|
356
|
-
await writeHealthyCondaMeta(
|
|
357
|
-
await writeFakeManagedConda(
|
|
358
|
-
const
|
|
343
|
+
test('Bin readiness rejects the previous Conda version and accepts the pinned version', async () => {
|
|
344
|
+
const staleRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-bin-conda-version-stale-'))
|
|
345
|
+
await writeHealthyCondaMeta(staleRoot, 'win32', '26.3.2')
|
|
346
|
+
await writeFakeManagedConda(staleRoot, 'win32')
|
|
347
|
+
const staleBin = createBin(staleRoot, 'win32')
|
|
359
348
|
|
|
360
|
-
await
|
|
361
|
-
assert.equal(
|
|
349
|
+
await staleBin.tryList()
|
|
350
|
+
assert.equal(staleBin.correct_conda, false)
|
|
362
351
|
|
|
363
|
-
await
|
|
352
|
+
const currentRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-bin-conda-version-current-'))
|
|
353
|
+
await writeHealthyCondaMeta(currentRoot, 'win32')
|
|
354
|
+
await writeFakeManagedConda(currentRoot, 'win32')
|
|
355
|
+
const currentBin = createBin(currentRoot, 'win32')
|
|
364
356
|
|
|
365
|
-
await
|
|
366
|
-
assert.equal(
|
|
357
|
+
await currentBin.tryList()
|
|
358
|
+
assert.equal(currentBin.correct_conda, true)
|
|
367
359
|
})
|
|
368
360
|
|
|
369
361
|
test('Conda install keeps the old runtime when the replacement installer download fails', async () => {
|
|
@@ -382,10 +374,9 @@ test('Conda install keeps the old runtime when the replacement installer downloa
|
|
|
382
374
|
/download failed/
|
|
383
375
|
)
|
|
384
376
|
assert.equal(await pathExists(oldRuntimeFile), true)
|
|
385
|
-
assert.equal(await pathExists(path.join(miniforge, CONDA_RUNTIME_MARKER)), false)
|
|
386
377
|
})
|
|
387
378
|
|
|
388
|
-
test('Conda install
|
|
379
|
+
test('Conda install propagates bootstrap failure after replacing the runtime', async () => {
|
|
389
380
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-bootstrap-fails-'))
|
|
390
381
|
await createMiniforge(root)
|
|
391
382
|
const kernel = createKernel(root, 'darwin')
|
|
@@ -405,7 +396,6 @@ test('Conda install leaves the runtime unmarked when bootstrap fails after repla
|
|
|
405
396
|
createConda(kernel)._install({ dependencies: [] }, () => {}),
|
|
406
397
|
/bootstrap failed/
|
|
407
398
|
)
|
|
408
|
-
assert.equal(await pathExists(path.join(root, 'bin', 'miniforge', CONDA_RUNTIME_MARKER)), false)
|
|
409
399
|
})
|
|
410
400
|
|
|
411
401
|
test('Conda install reports manual recovery when the old runtime cannot be removed', async () => {
|