pinokiod 7.5.0 → 7.5.2
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-meta.js +13 -13
- package/kernel/bin/conda.js +19 -45
- package/kernel/bin/ffmpeg.js +1 -1
- package/kernel/bin/setup.js +3 -0
- package/kernel/shell.js +1 -3
- package/package.json +1 -1
- package/server/index.js +2 -1
- package/test/conda-bin.test.js +14 -19
- package/test/ffmpeg-bin.test.js +12 -2
package/kernel/bin/conda-meta.js
CHANGED
|
@@ -2,21 +2,21 @@ const fs = require('fs')
|
|
|
2
2
|
const path = require('path')
|
|
3
3
|
const { execFile } = require('child_process')
|
|
4
4
|
|
|
5
|
-
async function buildCondaListFromMeta(
|
|
5
|
+
async function buildCondaListFromMeta(minicondaPath, useCondaList) {
|
|
6
6
|
if (!useCondaList) {
|
|
7
|
-
const metaOutput = await readFromMeta(
|
|
7
|
+
const metaOutput = await readFromMeta(minicondaPath)
|
|
8
8
|
if (metaOutput) {
|
|
9
9
|
return { response: metaOutput, source: 'conda-meta' }
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
return await runCondaList(
|
|
12
|
+
return await runCondaList(minicondaPath)
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
async function readFromMeta(
|
|
16
|
-
if (!
|
|
15
|
+
async function readFromMeta(minicondaPath) {
|
|
16
|
+
if (!minicondaPath) {
|
|
17
17
|
return null
|
|
18
18
|
}
|
|
19
|
-
const metaDir = path.join(
|
|
19
|
+
const metaDir = path.join(minicondaPath, 'conda-meta')
|
|
20
20
|
let entries
|
|
21
21
|
try {
|
|
22
22
|
entries = await fs.promises.readdir(metaDir, { withFileTypes: true })
|
|
@@ -53,8 +53,8 @@ async function readFromMeta(condaRootPath) {
|
|
|
53
53
|
return lines.join('\n')
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
async function runCondaList(
|
|
57
|
-
const condaBinary = resolveCondaBinary(
|
|
56
|
+
async function runCondaList(minicondaPath) {
|
|
57
|
+
const condaBinary = resolveCondaBinary(minicondaPath)
|
|
58
58
|
if (!condaBinary) {
|
|
59
59
|
return { response: '', source: 'conda-list' }
|
|
60
60
|
}
|
|
@@ -69,18 +69,18 @@ async function runCondaList(condaRootPath) {
|
|
|
69
69
|
})
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
function resolveCondaBinary(
|
|
72
|
+
function resolveCondaBinary(minicondaPath) {
|
|
73
73
|
if (process.platform === 'win32') {
|
|
74
|
-
if (
|
|
75
|
-
const scriptPath = path.join(
|
|
74
|
+
if (minicondaPath) {
|
|
75
|
+
const scriptPath = path.join(minicondaPath, 'Scripts', 'conda.exe')
|
|
76
76
|
if (fs.existsSync(scriptPath)) {
|
|
77
77
|
return scriptPath
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
return 'conda'
|
|
81
81
|
}
|
|
82
|
-
if (
|
|
83
|
-
const binPath = path.join(
|
|
82
|
+
if (minicondaPath) {
|
|
83
|
+
const binPath = path.join(minicondaPath, 'bin', 'conda')
|
|
84
84
|
if (fs.existsSync(binPath)) {
|
|
85
85
|
return binPath
|
|
86
86
|
}
|
package/kernel/bin/conda.js
CHANGED
|
@@ -16,12 +16,7 @@ const {
|
|
|
16
16
|
const MINIFORGE_RELEASE = "26.3.2-3"
|
|
17
17
|
const MINIFORGE_BASE_URL = `https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_RELEASE}`
|
|
18
18
|
const CONDA_ROOT_DIR = "miniforge"
|
|
19
|
-
const
|
|
20
|
-
const PINOKIO_CONDA_RUNTIME = {
|
|
21
|
-
distribution: "miniforge",
|
|
22
|
-
release: MINIFORGE_RELEASE,
|
|
23
|
-
epoch: 1,
|
|
24
|
-
}
|
|
19
|
+
const LEGACY_CONDA_ROOT_DIR = "miniconda"
|
|
25
20
|
|
|
26
21
|
class Conda {
|
|
27
22
|
description = "Pinokio uses Conda to install various useful programs in an isolated manner."
|
|
@@ -54,26 +49,8 @@ class Conda {
|
|
|
54
49
|
sqlitePinnedSpec(this.kernel.platform),
|
|
55
50
|
].join("\n")
|
|
56
51
|
}
|
|
57
|
-
|
|
58
|
-
return this.kernel.bin
|
|
59
|
-
}
|
|
60
|
-
async hasCurrentRuntimeStamp() {
|
|
61
|
-
try {
|
|
62
|
-
const value = await fs.promises.readFile(this.runtimeStampPath(), "utf8")
|
|
63
|
-
const runtime = JSON.parse(value)
|
|
64
|
-
return !!(runtime &&
|
|
65
|
-
runtime.distribution === PINOKIO_CONDA_RUNTIME.distribution &&
|
|
66
|
-
runtime.release === PINOKIO_CONDA_RUNTIME.release &&
|
|
67
|
-
runtime.epoch === PINOKIO_CONDA_RUNTIME.epoch)
|
|
68
|
-
} catch (e) {
|
|
69
|
-
return false
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
async writeRuntimeStamp() {
|
|
73
|
-
await fs.promises.writeFile(
|
|
74
|
-
this.runtimeStampPath(),
|
|
75
|
-
`${JSON.stringify(PINOKIO_CONDA_RUNTIME, null, 2)}\n`
|
|
76
|
-
)
|
|
52
|
+
async hasCondaMeta() {
|
|
53
|
+
return await this.kernel.exists(`bin/${CONDA_ROOT_DIR}/conda-meta`)
|
|
77
54
|
}
|
|
78
55
|
env() {
|
|
79
56
|
let base = {
|
|
@@ -100,6 +77,9 @@ class Conda {
|
|
|
100
77
|
if (this.kernel.platform !== "win32") {
|
|
101
78
|
return
|
|
102
79
|
}
|
|
80
|
+
if (!(await this.hasCondaMeta())) {
|
|
81
|
+
return
|
|
82
|
+
}
|
|
103
83
|
const activateDir = this.kernel.bin.path(`${CONDA_ROOT_DIR}/etc/conda/activate.d`)
|
|
104
84
|
await fs.promises.mkdir(activateDir, { recursive: true }).catch(() => {})
|
|
105
85
|
await fs.promises.writeFile(
|
|
@@ -141,12 +121,12 @@ remote_connect_timeout_secs: 20.0
|
|
|
141
121
|
remote_read_timeout_secs: 300.0
|
|
142
122
|
remote_max_retries: 6
|
|
143
123
|
report_errors: false`)
|
|
144
|
-
let pinned_exists = await this.
|
|
124
|
+
let pinned_exists = await this.hasCondaMeta()
|
|
145
125
|
if (pinned_exists) {
|
|
146
126
|
await fs.promises.writeFile(this.kernel.path(`bin/${CONDA_ROOT_DIR}/conda-meta/pinned`), this.pinnedPackages())
|
|
127
|
+
await this.ensureSslCertDirOverride()
|
|
128
|
+
await this.ensureCompatibilityAlias()
|
|
147
129
|
}
|
|
148
|
-
await this.ensureSslCertDirOverride()
|
|
149
|
-
await this.ensureCompatibilityAlias()
|
|
150
130
|
}
|
|
151
131
|
}
|
|
152
132
|
async check() {
|
|
@@ -228,10 +208,10 @@ report_errors: false`)
|
|
|
228
208
|
const installer_url = this.urls[this.kernel.platform][this.kernel.arch]
|
|
229
209
|
const installer = this.installer[this.kernel.platform]
|
|
230
210
|
const install_path = this.kernel.bin.path(CONDA_ROOT_DIR)
|
|
231
|
-
const
|
|
211
|
+
const legacy_path = this.kernel.bin.path(LEGACY_CONDA_ROOT_DIR)
|
|
232
212
|
let install_path_exists = await this.kernel.exists(`bin/${CONDA_ROOT_DIR}`)
|
|
233
|
-
let
|
|
234
|
-
if (install_path_exists ||
|
|
213
|
+
let legacy_path_exists = await this.kernel.exists(`bin/${LEGACY_CONDA_ROOT_DIR}`)
|
|
214
|
+
if (install_path_exists || legacy_path_exists) {
|
|
235
215
|
console.log("Install path already exists. Will replace after installer download...", install_path)
|
|
236
216
|
} else {
|
|
237
217
|
console.log("Install path does not exist. Installing...")
|
|
@@ -240,10 +220,10 @@ report_errors: false`)
|
|
|
240
220
|
ondata({ raw: `downloading installer: ${installer_url}...\r\n` })
|
|
241
221
|
await this.kernel.bin.download(installer_url, installer, ondata)
|
|
242
222
|
|
|
243
|
-
|
|
244
|
-
if (
|
|
245
|
-
console.log("Removing
|
|
246
|
-
await this.removeInstallPath(
|
|
223
|
+
legacy_path_exists = await this.kernel.exists(`bin/${LEGACY_CONDA_ROOT_DIR}`)
|
|
224
|
+
if (legacy_path_exists) {
|
|
225
|
+
console.log("Removing legacy install path...", legacy_path)
|
|
226
|
+
await this.removeInstallPath(legacy_path)
|
|
247
227
|
}
|
|
248
228
|
install_path_exists = await this.kernel.exists(`bin/${CONDA_ROOT_DIR}`)
|
|
249
229
|
if (install_path_exists) {
|
|
@@ -309,7 +289,6 @@ report_errors: false`)
|
|
|
309
289
|
)
|
|
310
290
|
}
|
|
311
291
|
await this.ensureSslCertDirOverride()
|
|
312
|
-
await this.writeRuntimeStamp()
|
|
313
292
|
await this.ensureCompatibilityAlias()
|
|
314
293
|
ondata({ raw: `Install finished\r\n` })
|
|
315
294
|
await this.kernel.bin.rm(installer, ondata)
|
|
@@ -346,9 +325,8 @@ report_errors: false`)
|
|
|
346
325
|
}
|
|
347
326
|
async ensureCompatibilityAlias() {
|
|
348
327
|
const target = this.kernel.bin.path(CONDA_ROOT_DIR)
|
|
349
|
-
const alias = this.kernel.bin.path(
|
|
350
|
-
|
|
351
|
-
if (!targetExists) {
|
|
328
|
+
const alias = this.kernel.bin.path(LEGACY_CONDA_ROOT_DIR)
|
|
329
|
+
if (!(await this.hasCondaMeta())) {
|
|
352
330
|
return
|
|
353
331
|
}
|
|
354
332
|
const aliasExists = await fs.promises.lstat(alias).then(() => true).catch(() => false)
|
|
@@ -378,10 +356,6 @@ report_errors: false`)
|
|
|
378
356
|
for(let p of this.paths[this.kernel.platform]) {
|
|
379
357
|
let e = await this.kernel.bin.exists(p)
|
|
380
358
|
if (e && this.kernel.bin.correct_conda) {
|
|
381
|
-
if (!(await this.hasCurrentRuntimeStamp())) {
|
|
382
|
-
console.log("Pinokio Conda runtime changed; marking Conda invalid")
|
|
383
|
-
return false
|
|
384
|
-
}
|
|
385
359
|
return true
|
|
386
360
|
}
|
|
387
361
|
}
|
|
@@ -389,7 +363,7 @@ report_errors: false`)
|
|
|
389
363
|
}
|
|
390
364
|
|
|
391
365
|
async uninstall(req, ondata) {
|
|
392
|
-
await this.kernel.bin.rm(
|
|
366
|
+
await this.kernel.bin.rm(LEGACY_CONDA_ROOT_DIR, ondata)
|
|
393
367
|
return this.kernel.bin.rm(CONDA_ROOT_DIR, ondata)
|
|
394
368
|
}
|
|
395
369
|
|
package/kernel/bin/ffmpeg.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const RELEASE_VERSION = "8.1.2"
|
|
2
2
|
const CONDA_SPEC = `ffmpeg=${RELEASE_VERSION}`
|
|
3
|
-
const CONDA_CHANNEL_FLAGS = "
|
|
3
|
+
const CONDA_CHANNEL_FLAGS = "-c conda-forge"
|
|
4
4
|
|
|
5
5
|
class Ffmpeg {
|
|
6
6
|
description = "Installs FFmpeg for audio and video processing."
|
package/kernel/bin/setup.js
CHANGED
|
@@ -14,6 +14,7 @@ module.exports = {
|
|
|
14
14
|
"node",
|
|
15
15
|
"huggingface",
|
|
16
16
|
"git",
|
|
17
|
+
"ffmpeg",
|
|
17
18
|
// "caddy"
|
|
18
19
|
]
|
|
19
20
|
if (platform !== "win32") {
|
|
@@ -183,6 +184,7 @@ module.exports = {
|
|
|
183
184
|
"node",
|
|
184
185
|
"huggingface",
|
|
185
186
|
"git",
|
|
187
|
+
"ffmpeg",
|
|
186
188
|
]
|
|
187
189
|
if (platform !== "win32") {
|
|
188
190
|
conda_requirements.push("tmux")
|
|
@@ -222,6 +224,7 @@ module.exports = {
|
|
|
222
224
|
"huggingface",
|
|
223
225
|
"git",
|
|
224
226
|
"caddy",
|
|
227
|
+
"ffmpeg",
|
|
225
228
|
]
|
|
226
229
|
if (platform === "win32") {
|
|
227
230
|
requirements.push({ name: "registry" })
|
package/kernel/shell.js
CHANGED
|
@@ -1245,8 +1245,6 @@ class Shell {
|
|
|
1245
1245
|
this.env.PIP_REQUIRE_VIRTUALENV = "true"
|
|
1246
1246
|
}
|
|
1247
1247
|
|
|
1248
|
-
this.env.UV_PYTHON_PREFERENCE="only-managed"
|
|
1249
|
-
|
|
1250
1248
|
// 2. venv
|
|
1251
1249
|
|
|
1252
1250
|
/*
|
|
@@ -1322,7 +1320,7 @@ class Shell {
|
|
|
1322
1320
|
if (use_uv) {
|
|
1323
1321
|
// when python version is specified as venv.python => use uv
|
|
1324
1322
|
venv_activation = [
|
|
1325
|
-
`uv venv ${shellEnvPath}${python_version}`,
|
|
1323
|
+
`uv venv --managed-python ${shellEnvPath}${python_version}`,
|
|
1326
1324
|
activate_command,
|
|
1327
1325
|
// `uv pip install --upgrade pip setuptools wheel`,
|
|
1328
1326
|
deactivate_path,
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -6013,7 +6013,7 @@ class Server {
|
|
|
6013
6013
|
this.kernel.store.set("version", this.version.pinokiod)
|
|
6014
6014
|
console.log("[DONE] Updating to the new version")
|
|
6015
6015
|
console.log("not up to date. update py.")
|
|
6016
|
-
// remove ~/bin/py
|
|
6016
|
+
// remove ~/bin/miniconda/py
|
|
6017
6017
|
let p = path.resolve(home, "bin/py")
|
|
6018
6018
|
console.log(`[TRY] reset ${p}`)
|
|
6019
6019
|
await fse.remove(p)
|
|
@@ -10034,6 +10034,7 @@ class Server {
|
|
|
10034
10034
|
return
|
|
10035
10035
|
}
|
|
10036
10036
|
// check bin folder
|
|
10037
|
+
// let bin_path = this.kernel.path("bin/miniconda")
|
|
10037
10038
|
// let bin_exists = await this.exists(bin_path)
|
|
10038
10039
|
// if (!bin_exists) {
|
|
10039
10040
|
// res.redirect("/setup")
|
package/test/conda-bin.test.js
CHANGED
|
@@ -46,17 +46,6 @@ async function createLegacyMiniconda(root) {
|
|
|
46
46
|
return createCondaRoot(root, 'miniconda')
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
async function writeCurrentRuntimeStamp(root) {
|
|
50
|
-
await fs.writeFile(
|
|
51
|
-
path.join(root, 'bin', 'miniforge', '.pinokio-runtime.json'),
|
|
52
|
-
`${JSON.stringify({
|
|
53
|
-
distribution: 'miniforge',
|
|
54
|
-
release: '26.3.2-3',
|
|
55
|
-
epoch: 1,
|
|
56
|
-
}, null, 2)}\n`
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
|
|
60
49
|
function createConda(kernel) {
|
|
61
50
|
const conda = new Conda()
|
|
62
51
|
conda.kernel = kernel
|
|
@@ -81,6 +70,20 @@ test('Conda uses Miniforge assets and writes conda-forge-only config', async ()
|
|
|
81
70
|
assert.doesNotMatch(condarc, /bin\/miniconda\/envs/)
|
|
82
71
|
assert.doesNotMatch(condarc, /\bdefaults\b/)
|
|
83
72
|
assert.doesNotMatch(condarc, /auto_accept_tos/)
|
|
73
|
+
assert.equal(await pathExists(path.join(root, 'bin', 'miniforge')), false)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
test('Conda init writes activation hooks only after Miniforge exists', async () => {
|
|
77
|
+
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-init-hooks-'))
|
|
78
|
+
await fs.mkdir(path.join(root, 'bin', 'miniforge', 'conda-meta'), { recursive: true })
|
|
79
|
+
const conda = createConda(createKernel(root))
|
|
80
|
+
|
|
81
|
+
await conda.init()
|
|
82
|
+
|
|
83
|
+
assert.equal(
|
|
84
|
+
await pathExists(path.join(root, 'bin', 'miniforge', 'etc', 'conda', 'activate.d', 'zz_pinokio_unset_ssl_cert_dir-win.bat')),
|
|
85
|
+
true
|
|
86
|
+
)
|
|
84
87
|
})
|
|
85
88
|
|
|
86
89
|
test('Conda pins Python 3.10.20 consistently across platforms', async () => {
|
|
@@ -204,14 +207,6 @@ test('Conda installed stays false when metadata check already marked Conda inval
|
|
|
204
207
|
assert.equal(await createConda(kernel).installed(), false)
|
|
205
208
|
})
|
|
206
209
|
|
|
207
|
-
test('Conda installed returns false for old Conda runtimes without the Miniforge stamp', async () => {
|
|
208
|
-
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-runtime-stale-'))
|
|
209
|
-
await createMiniforge(root)
|
|
210
|
-
const kernel = createKernel(root)
|
|
211
|
-
|
|
212
|
-
assert.equal(await createConda(kernel).installed(), false)
|
|
213
|
-
})
|
|
214
|
-
|
|
215
210
|
test('Conda install keeps the old runtime when the replacement installer download fails', async () => {
|
|
216
211
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-download-fails-'))
|
|
217
212
|
const miniconda = await createLegacyMiniconda(root)
|
package/test/ffmpeg-bin.test.js
CHANGED
|
@@ -2,6 +2,7 @@ const assert = require('node:assert/strict')
|
|
|
2
2
|
const test = require('node:test')
|
|
3
3
|
|
|
4
4
|
const Ffmpeg = require('../kernel/bin/ffmpeg')
|
|
5
|
+
const Setup = require('../kernel/bin/setup')
|
|
5
6
|
|
|
6
7
|
function createKernel(platform = 'win32') {
|
|
7
8
|
return {
|
|
@@ -34,7 +35,7 @@ test('FFmpeg bin installs pinned ffmpeg into base Conda on Windows', async () =>
|
|
|
34
35
|
assert.equal(calls.length, 1)
|
|
35
36
|
assert.deepEqual(calls[0].message, [
|
|
36
37
|
'conda clean -y --all',
|
|
37
|
-
'conda install -y
|
|
38
|
+
'conda install -y -c conda-forge ffmpeg=8.1.2',
|
|
38
39
|
])
|
|
39
40
|
assert.equal(calls[0].env, undefined)
|
|
40
41
|
assert.equal(calls[0].message.some((command) => /ffmpeg-env|conda create|-p /.test(command)), false)
|
|
@@ -51,7 +52,7 @@ test('FFmpeg bin installs pinned ffmpeg into base Conda consistently across plat
|
|
|
51
52
|
|
|
52
53
|
assert.deepEqual(calls[0].message, [
|
|
53
54
|
'conda clean -y --all',
|
|
54
|
-
'conda install -y
|
|
55
|
+
'conda install -y -c conda-forge ffmpeg=8.1.2',
|
|
55
56
|
])
|
|
56
57
|
})
|
|
57
58
|
|
|
@@ -70,3 +71,12 @@ test('FFmpeg installed check requires the base Conda package at the pinned versi
|
|
|
70
71
|
kernel.bin.installed.conda_versions = {}
|
|
71
72
|
assert.equal(await ffmpeg.installed(), false)
|
|
72
73
|
})
|
|
74
|
+
|
|
75
|
+
test('setup presets bundle FFmpeg into Conda bootstrap and keep the module check', () => {
|
|
76
|
+
const kernel = { gpu: null }
|
|
77
|
+
for (const preset of ['ai', 'dev', 'advanced_dev']) {
|
|
78
|
+
const config = Setup[preset](kernel)
|
|
79
|
+
assert.equal(config.conda_requirements.includes('ffmpeg'), true)
|
|
80
|
+
assert.equal(config.requirements.some((requirement) => requirement.name === 'ffmpeg'), true)
|
|
81
|
+
}
|
|
82
|
+
})
|