pinokiod 7.4.3 → 7.5.0

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.
@@ -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(minicondaPath, useCondaList) {
5
+ async function buildCondaListFromMeta(condaRootPath, useCondaList) {
6
6
  if (!useCondaList) {
7
- const metaOutput = await readFromMeta(minicondaPath)
7
+ const metaOutput = await readFromMeta(condaRootPath)
8
8
  if (metaOutput) {
9
9
  return { response: metaOutput, source: 'conda-meta' }
10
10
  }
11
11
  }
12
- return await runCondaList(minicondaPath)
12
+ return await runCondaList(condaRootPath)
13
13
  }
14
14
 
15
- async function readFromMeta(minicondaPath) {
16
- if (!minicondaPath) {
15
+ async function readFromMeta(condaRootPath) {
16
+ if (!condaRootPath) {
17
17
  return null
18
18
  }
19
- const metaDir = path.join(minicondaPath, 'conda-meta')
19
+ const metaDir = path.join(condaRootPath, '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(minicondaPath) {
53
53
  return lines.join('\n')
54
54
  }
55
55
 
56
- async function runCondaList(minicondaPath) {
57
- const condaBinary = resolveCondaBinary(minicondaPath)
56
+ async function runCondaList(condaRootPath) {
57
+ const condaBinary = resolveCondaBinary(condaRootPath)
58
58
  if (!condaBinary) {
59
59
  return { response: '', source: 'conda-list' }
60
60
  }
@@ -69,18 +69,18 @@ async function runCondaList(minicondaPath) {
69
69
  })
70
70
  }
71
71
 
72
- function resolveCondaBinary(minicondaPath) {
72
+ function resolveCondaBinary(condaRootPath) {
73
73
  if (process.platform === 'win32') {
74
- if (minicondaPath) {
75
- const scriptPath = path.join(minicondaPath, 'Scripts', 'conda.exe')
74
+ if (condaRootPath) {
75
+ const scriptPath = path.join(condaRootPath, '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 (minicondaPath) {
83
- const binPath = path.join(minicondaPath, 'bin', 'conda')
82
+ if (condaRootPath) {
83
+ const binPath = path.join(condaRootPath, 'bin', 'conda')
84
84
  if (fs.existsSync(binPath)) {
85
85
  return binPath
86
86
  }
@@ -1,10 +1,11 @@
1
1
  const semver = require('semver')
2
2
 
3
- const CONDA_PIN_VERSION = "25.5.1"
3
+ const CONDA_PIN_VERSION = "26.3.2"
4
4
  const DEFAULT_SQLITE_PIN_VERSION = "3.47.2"
5
5
  const WINDOWS_SQLITE_PIN_VERSION = "3.53.2"
6
- const WINDOWS_PYTHON_SSL_FIX_SPEC = "python=3.10.20=*_1_cpython"
7
- const WINDOWS_PYTHON_SSL_FIX_VERSION = "3.10.20"
6
+ const PYTHON_PIN_VERSION = "3.10.20"
7
+ const PYTHON_INSTALL_SPEC = `python=${PYTHON_PIN_VERSION}`
8
+ const WINDOWS_PYTHON_SSL_FIX_SPEC = `${PYTHON_INSTALL_SPEC}=*_1_cpython`
8
9
 
9
10
  const sqlitePinVersion = (platform) => {
10
11
  return platform === "win32" ? WINDOWS_SQLITE_PIN_VERSION : DEFAULT_SQLITE_PIN_VERSION
@@ -28,15 +29,15 @@ const condaBuildNumber = (build) => {
28
29
  return buildNumber ? Number(buildNumber) : null
29
30
  }
30
31
 
31
- const isWindowsPythonSslFixed = (version, build) => {
32
+ const isExpectedPythonPinned = (platform, version, build) => {
32
33
  const coerced = semver.coerce(version)
33
34
  if (!coerced) {
34
35
  return false
35
36
  }
36
- if (!semver.satisfies(coerced, ">=3.10.20 <3.11.0")) {
37
+ if (!semver.eq(coerced, PYTHON_PIN_VERSION)) {
37
38
  return false
38
39
  }
39
- if (semver.eq(coerced, WINDOWS_PYTHON_SSL_FIX_VERSION)) {
40
+ if (platform === "win32") {
40
41
  const buildNumber = condaBuildNumber(build)
41
42
  return typeof buildNumber === "number" && buildNumber >= 1
42
43
  }
@@ -45,9 +46,10 @@ const isWindowsPythonSslFixed = (version, build) => {
45
46
 
46
47
  module.exports = {
47
48
  CONDA_PIN_VERSION,
49
+ PYTHON_INSTALL_SPEC,
48
50
  WINDOWS_PYTHON_SSL_FIX_SPEC,
49
51
  isExpectedSqlitePinned,
50
- isWindowsPythonSslFixed,
52
+ isExpectedPythonPinned,
51
53
  sqliteInstallSpec,
52
54
  sqlitePinnedSpec,
53
55
  }
@@ -1,50 +1,41 @@
1
1
  const fs = require('fs')
2
2
  const path = require('path')
3
- const fetch = require('cross-fetch')
4
3
  const { glob } = require('glob')
5
4
  const semver = require('semver')
6
5
  const { buildCondaListFromMeta } = require('./conda-meta')
7
6
  const {
8
7
  CONDA_PIN_VERSION,
8
+ PYTHON_INSTALL_SPEC,
9
9
  WINDOWS_PYTHON_SSL_FIX_SPEC,
10
+ isExpectedPythonPinned,
10
11
  isExpectedSqlitePinned,
11
- isWindowsPythonSslFixed,
12
12
  sqliteInstallSpec,
13
13
  sqlitePinnedSpec,
14
14
  } = require('./conda-pins')
15
15
 
16
+ const MINIFORGE_RELEASE = "26.3.2-3"
17
+ const MINIFORGE_BASE_URL = `https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_RELEASE}`
18
+ const CONDA_ROOT_DIR = "miniforge"
19
+ const CONDA_COMPAT_ROOT_DIR = "miniconda"
20
+ const PINOKIO_CONDA_RUNTIME = {
21
+ distribution: "miniforge",
22
+ release: MINIFORGE_RELEASE,
23
+ epoch: 1,
24
+ }
25
+
16
26
  class Conda {
17
27
  description = "Pinokio uses Conda to install various useful programs in an isolated manner."
18
28
  urls = {
19
29
  darwin: {
20
- //x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_23.5.2-0-MacOSX-x86_64.sh",
21
- //arm64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_23.5.2-0-MacOSX-arm64.sh"
22
- //x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_24.5.0-0-MacOSX-x86_64.sh",
23
- //arm64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_24.5.0-0-MacOSX-arm64.sh"
24
-
25
- //x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_24.11.1-0-MacOSX-x86_64.sh",
26
- //arm64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_24.11.1-0-MacOSX-arm64.sh"
27
-
28
- x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_25.1.1-2-MacOSX-x86_64.sh",
29
- arm64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_25.1.1-2-MacOSX-arm64.sh"
30
+ x64: `${MINIFORGE_BASE_URL}/Miniforge3-MacOSX-x86_64.sh`,
31
+ arm64: `${MINIFORGE_BASE_URL}/Miniforge3-MacOSX-arm64.sh`
30
32
  },
31
33
  win32: {
32
- //x64: "https://github.com/cocktailpeanut/miniconda/releases/download/v23.5.2/Miniconda3-py310_23.5.2-0-Windows-x86_64.exe",
33
- //x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_24.5.0-0-Windows-x86_64.exe"
34
-
35
- //x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_24.11.1-0-Windows-x86_64.exe"
36
- x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_25.1.1-2-Windows-x86_64.exe",
34
+ x64: `${MINIFORGE_BASE_URL}/Miniforge3-Windows-x86_64.exe`,
37
35
  },
38
36
  linux: {
39
- //x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_23.5.2-0-Linux-x86_64.sh",
40
- //arm64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_23.5.2-0-Linux-aarch64.sh"
41
- //x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_24.5.0-0-Linux-x86_64.sh",
42
- //arm64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_24.5.0-0-Linux-aarch64.sh"
43
-
44
- //x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_24.11.1-0-Linux-x86_64.sh",
45
- //arm64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_24.11.1-0-Linux-aarch64.sh"
46
- x64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_25.1.1-2-Linux-x86_64.sh",
47
- arm64: "https://repo.anaconda.com/miniconda/Miniconda3-py310_25.1.1-2-Linux-aarch64.sh"
37
+ x64: `${MINIFORGE_BASE_URL}/Miniforge3-Linux-x86_64.sh`,
38
+ arm64: `${MINIFORGE_BASE_URL}/Miniforge3-Linux-aarch64.sh`
48
39
  }
49
40
  }
50
41
  installer = {
@@ -53,9 +44,9 @@ class Conda {
53
44
  linux: "installer.sh"
54
45
  }
55
46
  paths = {
56
- darwin: [ "miniconda/etc/profile.d", "miniconda/bin", "miniconda/condabin", "miniconda/lib", "miniconda/Library/bin", "miniconda/pkgs", "miniconda" ],
57
- win32: ["miniconda/etc/profile.d", "miniconda/bin", "miniconda/Scripts", "miniconda/condabin", "miniconda/lib", "miniconda/Library/bin", "miniconda/pkgs", "miniconda"],
58
- linux: ["miniconda/etc/profile.d", "miniconda/bin", "miniconda/condabin", "miniconda/lib", "miniconda/Library/bin", "miniconda/pkgs", "miniconda"]
47
+ darwin: [ `${CONDA_ROOT_DIR}/etc/profile.d`, `${CONDA_ROOT_DIR}/bin`, `${CONDA_ROOT_DIR}/condabin`, `${CONDA_ROOT_DIR}/lib`, `${CONDA_ROOT_DIR}/Library/bin`, `${CONDA_ROOT_DIR}/pkgs`, CONDA_ROOT_DIR ],
48
+ win32: [`${CONDA_ROOT_DIR}/etc/profile.d`, `${CONDA_ROOT_DIR}/bin`, `${CONDA_ROOT_DIR}/Scripts`, `${CONDA_ROOT_DIR}/condabin`, `${CONDA_ROOT_DIR}/lib`, `${CONDA_ROOT_DIR}/Library/bin`, `${CONDA_ROOT_DIR}/pkgs`, CONDA_ROOT_DIR],
49
+ linux: [`${CONDA_ROOT_DIR}/etc/profile.d`, `${CONDA_ROOT_DIR}/bin`, `${CONDA_ROOT_DIR}/condabin`, `${CONDA_ROOT_DIR}/lib`, `${CONDA_ROOT_DIR}/Library/bin`, `${CONDA_ROOT_DIR}/pkgs`, CONDA_ROOT_DIR]
59
50
  }
60
51
  pinnedPackages() {
61
52
  return [
@@ -63,25 +54,45 @@ class Conda {
63
54
  sqlitePinnedSpec(this.kernel.platform),
64
55
  ].join("\n")
65
56
  }
57
+ runtimeStampPath() {
58
+ return this.kernel.bin.path(CONDA_ROOT_DIR, ".pinokio-runtime.json")
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
+ )
77
+ }
66
78
  env() {
67
79
  let base = {
68
- // CONDA_ROOT: this.kernel.bin.path("miniconda"),
69
- CONDA_PREFIX: this.kernel.bin.path("miniconda"),
70
- CONDA_ENVS_PATH: this.kernel.bin.path("miniconda/envs"),
71
- CONDA_PKGS_DIRS: this.kernel.bin.path("miniconda/pkgs"),
72
- PYTHON: this.kernel.bin.path("miniconda/python"),
80
+ CONDA_PREFIX: this.kernel.bin.path(CONDA_ROOT_DIR),
81
+ CONDA_ENVS_PATH: this.kernel.bin.path(`${CONDA_ROOT_DIR}/envs`),
82
+ CONDA_PKGS_DIRS: this.kernel.bin.path(`${CONDA_ROOT_DIR}/pkgs`),
83
+ PYTHON: this.kernel.bin.path(`${CONDA_ROOT_DIR}/python`),
73
84
  PATH: this.paths[this.kernel.platform].map((p) => {
74
85
  return this.kernel.bin.path(p)
75
86
  })
76
87
  }
77
88
  if (this.kernel.platform === "win32") {
78
- base.CONDA_BAT = this.kernel.bin.path("miniconda/condabin/conda.bat")
79
- base.CONDA_EXE = this.kernel.bin.path("miniconda/Scripts/conda.exe")
80
- base.CONDA_PYTHON_EXE = this.kernel.bin.path("miniconda/Scripts/python")
89
+ base.CONDA_BAT = this.kernel.bin.path(`${CONDA_ROOT_DIR}/condabin/conda.bat`)
90
+ base.CONDA_EXE = this.kernel.bin.path(`${CONDA_ROOT_DIR}/Scripts/conda.exe`)
91
+ base.CONDA_PYTHON_EXE = this.kernel.bin.path(`${CONDA_ROOT_DIR}/Scripts/python`)
81
92
  }
82
93
  if (this.kernel.platform === 'darwin') {
83
- base.TCL_LIBRARY = this.kernel.bin.path("miniconda/lib/tcl8.6")
84
- base.TK_LIBRARY = this.kernel.bin.path("miniconda/lib/tk8.6")
94
+ base.TCL_LIBRARY = this.kernel.bin.path(`${CONDA_ROOT_DIR}/lib/tcl8.6`)
95
+ base.TK_LIBRARY = this.kernel.bin.path(`${CONDA_ROOT_DIR}/lib/tk8.6`)
85
96
  }
86
97
  return base
87
98
  }
@@ -89,7 +100,7 @@ class Conda {
89
100
  if (this.kernel.platform !== "win32") {
90
101
  return
91
102
  }
92
- const activateDir = this.kernel.bin.path("miniconda/etc/conda/activate.d")
103
+ const activateDir = this.kernel.bin.path(`${CONDA_ROOT_DIR}/etc/conda/activate.d`)
93
104
  await fs.promises.mkdir(activateDir, { recursive: true }).catch(() => {})
94
105
  await fs.promises.writeFile(
95
106
  path.resolve(activateDir, "zz_pinokio_unset_ssl_cert_dir-win.bat"),
@@ -115,61 +126,31 @@ fi
115
126
  )
116
127
  }
117
128
  async init() {
118
- //
119
129
  if (this.kernel.homedir) {
120
- // let exists = await this.kernel.exists("condarc")
121
130
  console.log("condarc init")
122
- // if (!exists) {
123
131
  await fs.promises.writeFile(this.kernel.path('condarc'), `channels:
124
132
  - conda-forge
125
- - defaults
126
133
  channel_priority: flexible
127
134
  create_default_packages:
128
- - python=3.10
135
+ - ${PYTHON_INSTALL_SPEC}
129
136
  envs_dirs:
130
- - ${this.kernel.bin.path("miniconda/envs")}
131
- plugins:
132
- anaconda_telemetry: false
133
- auto_accept_tos: true
137
+ - ${this.kernel.bin.path(`${CONDA_ROOT_DIR}/envs`)}
134
138
  pkgs_dirs:
135
- - ${this.kernel.bin.path("miniconda/pkgs")}
139
+ - ${this.kernel.bin.path(`${CONDA_ROOT_DIR}/pkgs`)}
136
140
  remote_connect_timeout_secs: 20.0
137
141
  remote_read_timeout_secs: 300.0
138
142
  remote_max_retries: 6
139
143
  report_errors: false`)
140
- //repodata_threads: 4
141
- //fetch_threads: 5
142
- //report_errors: false`)
143
- // }
144
- let pinned_exists = await this.kernel.exists("bin/miniconda/conda-meta")
144
+ let pinned_exists = await this.kernel.exists(`bin/${CONDA_ROOT_DIR}/conda-meta`)
145
145
  if (pinned_exists) {
146
- //await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda ==24.11.3`)
147
- await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), this.pinnedPackages())
148
- // await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), "")
149
- //sqlite ==3.47.2`)
150
- // await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda=24.9.0`)
151
- // await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda=24.11.2
152
- //conda-libmamba-solver=24.11.1`)
153
- // await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda=24.7.1
154
- //conda-libmamba-solver=24.7.0`)
146
+ await fs.promises.writeFile(this.kernel.path(`bin/${CONDA_ROOT_DIR}/conda-meta/pinned`), this.pinnedPackages())
155
147
  }
156
148
  await this.ensureSslCertDirOverride()
149
+ await this.ensureCompatibilityAlias()
157
150
  }
158
151
  }
159
- // async init() {
160
- // let exists = await this.kernel.bin.exists("miniconda/condarc")
161
- // console.log("condarc exists?", exists)
162
- // if (!exists) {
163
- // console.log("write to condarc")
164
- // await fs.promises.writeFile(this.kernel.bin.path('miniconda/condarc'), `channels:
165
- // - conda-forge
166
- // - defaults
167
- // create_default_packages:
168
- // - python=3.10`)
169
- // }
170
- // }
171
152
  async check() {
172
- let res = await buildCondaListFromMeta(this.kernel.bin.path("miniconda"))
153
+ let res = await buildCondaListFromMeta(this.kernel.bin.path(CONDA_ROOT_DIR))
173
154
 
174
155
  let lines = res.response.split(/[\r\n]+/)
175
156
  let conda_check = {}
@@ -189,20 +170,12 @@ report_errors: false`)
189
170
  conda_builds[name] = build
190
171
  if (name === "conda") {
191
172
  conda_check.conda = true
192
- // //if (String(version) === "24.11.1") {
193
- // if (String(version) === "24.11.3") {
194
- // conda_check.conda = true
195
- // }
196
173
  }
197
174
  // check conda-libmamba-solver is up to date
198
175
  // sometimes it just fails silently so need to check
199
176
  if (name === "conda-libmamba-solver") {
200
- //if (String(version) === "24.7.0") {
201
- let channel = chunks[3]
202
177
  let coerced = semver.coerce(version)
203
- //let mamba_requirement = ">=24.11.1"
204
178
  let mamba_requirement = ">=25.4.0"
205
- //if (semver.satisfies(coerced, mamba_requirement) && channel === "conda-forge") {
206
179
  if (semver.satisfies(coerced, mamba_requirement)) {
207
180
  conda_check.mamba = true
208
181
  }
@@ -225,7 +198,7 @@ report_errors: false`)
225
198
  //}
226
199
  }
227
200
  if (name === "python") {
228
- conda_check.python = this.kernel.platform !== "win32" || isWindowsPythonSslFixed(version, build)
201
+ conda_check.python = isExpectedPythonPinned(this.kernel.platform, version, build)
229
202
  }
230
203
  }
231
204
  } else {
@@ -237,8 +210,7 @@ report_errors: false`)
237
210
  this.kernel.bin.installed.conda = conda
238
211
  this.kernel.bin.installed.conda_versions = conda_versions
239
212
  this.kernel.bin.installed.conda_builds = conda_builds
240
- return conda_check.conda && conda_check.mamba && conda_check.sqlite && (this.kernel.platform !== "win32" || conda_check.python)
241
- //return conda_check.conda && conda_check.mamba
213
+ return conda_check.conda && conda_check.mamba && conda_check.sqlite && conda_check.python
242
214
  }
243
215
  async install(req, ondata) {
244
216
  for(let i=0; i<5; i++) {
@@ -255,12 +227,12 @@ report_errors: false`)
255
227
  async _install(req, ondata) {
256
228
  const installer_url = this.urls[this.kernel.platform][this.kernel.arch]
257
229
  const installer = this.installer[this.kernel.platform]
258
- const install_path = this.kernel.bin.path("miniconda")
259
- let install_path_exists = await this.kernel.exists("bin/miniconda")
260
- if (install_path_exists) {
261
- console.log("Install path already exists. Removing...", install_path)
262
- await fs.promises.rm(install_path, { recursive: true }).catch((e) => {
263
- })
230
+ const install_path = this.kernel.bin.path(CONDA_ROOT_DIR)
231
+ const compat_path = this.kernel.bin.path(CONDA_COMPAT_ROOT_DIR)
232
+ let install_path_exists = await this.kernel.exists(`bin/${CONDA_ROOT_DIR}`)
233
+ let compat_path_exists = await this.kernel.exists(`bin/${CONDA_COMPAT_ROOT_DIR}`)
234
+ if (install_path_exists || compat_path_exists) {
235
+ console.log("Install path already exists. Will replace after installer download...", install_path)
264
236
  } else {
265
237
  console.log("Install path does not exist. Installing...")
266
238
  }
@@ -268,6 +240,17 @@ report_errors: false`)
268
240
  ondata({ raw: `downloading installer: ${installer_url}...\r\n` })
269
241
  await this.kernel.bin.download(installer_url, installer, ondata)
270
242
 
243
+ compat_path_exists = await this.kernel.exists(`bin/${CONDA_COMPAT_ROOT_DIR}`)
244
+ if (compat_path_exists) {
245
+ console.log("Removing compatibility install path...", compat_path)
246
+ await this.removeInstallPath(compat_path)
247
+ }
248
+ install_path_exists = await this.kernel.exists(`bin/${CONDA_ROOT_DIR}`)
249
+ if (install_path_exists) {
250
+ console.log("Removing existing install path...", install_path)
251
+ await this.removeInstallPath(install_path)
252
+ }
253
+
271
254
  // 2. run the script
272
255
  ondata({ raw: `running installer: ${installer}...\r\n` })
273
256
 
@@ -284,35 +267,13 @@ report_errors: false`)
284
267
  })
285
268
 
286
269
  // set pinned
287
- let pinned_exists = await this.kernel.exists("bin/miniconda/conda-meta")
270
+ let pinned_exists = await this.kernel.exists(`bin/${CONDA_ROOT_DIR}/conda-meta`)
288
271
  if (pinned_exists) {
289
- //await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda=24.11.1`)
290
- //await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda ==24.11.3`)
291
- await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), this.pinnedPackages())
292
- //await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), "sqlite ==3.47.2")
293
- //await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), "")
294
- //sqlite ==3.47.2`)
295
- // await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda=24.9.0`)
296
- // await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda=24.11.2
297
- //conda-libmamba-solver=24.11.1`)
298
- // await fs.promises.writeFile(this.kernel.path('bin/miniconda/conda-meta/pinned'), `conda=24.7.1
299
- //conda-libmamba-solver=24.7.0`)
272
+ await fs.promises.writeFile(this.kernel.path(`bin/${CONDA_ROOT_DIR}/conda-meta/pinned`), this.pinnedPackages())
300
273
  }
301
- //// await this.activate()
302
- // await fs.promises.writeFile(this.kernel.bin.path('miniconda/condarc'), `channels:
303
- // - conda-forge
304
- // - defaults
305
- //create_default_packages:
306
- // - python=3.10`)
307
-
308
-
309
- // 1. right after installing conda==24.11.1, run conda update --all
310
- // 2. The pinned file says conda-libmamba-solver=24.11.1
311
- // 3. so after conda update --all, it should be conda-libmamba-solver=24.11.1
312
274
 
313
275
  let mods = this.kernel.bin.mods.filter((m) => {
314
276
  return req.dependencies.includes(m.name)
315
- // return ["zip", "uv", "node", "huggingface", "gxx", "git", "ffmpeg", "caddy"].includes(m.name)
316
277
  }).map((m) => {
317
278
  if (m.mod.cmd) {
318
279
  return m.mod.cmd()
@@ -323,113 +284,86 @@ report_errors: false`)
323
284
  console.log("Conda dependencies to install", { mods })
324
285
 
325
286
  let condaPackages = [
287
+ this.kernel.platform === "win32" ? `"${WINDOWS_PYTHON_SSL_FIX_SPEC}"` : `"${PYTHON_INSTALL_SPEC}"`,
326
288
  `"${sqliteInstallSpec(this.kernel.platform)}"`,
327
289
  `"conda-libmamba-solver>=25.4.0"`,
328
290
  ]
329
- if (this.kernel.platform === "win32") {
330
- condaPackages.unshift(`"${WINDOWS_PYTHON_SSL_FIX_SPEC}"`)
331
- }
332
291
 
333
292
  let cmds = [
334
- //"conda clean -y --index-cache",
335
293
  "conda clean -y --all",
336
- `conda install -y -c conda-forge ${condaPackages.join(" ")} ${mods}`.trim(),
337
-
338
- // `conda config --file ${this.kernel.path('condarc')} --set remote_connect_timeout_secs 20`,
339
- // `conda config --file ${this.kernel.path('condarc')} --set remote_read_timeout_secs 300`,
340
- // `conda config --file ${this.kernel.path('condarc')} --set remote_max_retries 6`,
341
- // `conda config --file ${this.kernel.path('condarc')} --set repodata_threads 4`,
342
- // `conda config --file ${this.kernel.path('condarc')} --set fetch_threads 5`,
343
- // `conda config --file ${this.kernel.path('condarc')} --set report_errors false`,
344
-
345
-
346
-
347
- // `conda config --file ${this.kernel.path('condarc')} --set auto_update_conda false`,
348
- // "conda install -y -c conda-forge conda-libmamba-solver=24.11.1",
349
- // "conda install libsqlite --force-reinstall -y",
350
- // `conda config --file ${this.kernel.path('condarc')} --set auto_update_conda False`,
351
- //"conda install -y conda=24.9.0 -vvv --strict-channel-priority",
352
- //"conda install -y conda=24.11.3 conda-libmamba-solver=24.11.1 -vvv",
353
- //"conda install -y conda-libmamba-solver=24.7.0 conda=24.7.1 -vvv --strict-channel-priority",
354
- //"conda install -y conda-libmamba-solver=24.11.1 conda=24.7.1",
355
- //"conda install -y conda-libmamba-solver=24.11.1 conda=24.11.2",
356
- //"conda update -y conda-libmamba-solver",
357
- //"conda update -y conda sqlite",// -vvv --debug",
358
-
359
-
360
- // "conda update -y conda",// -vvv --debug",
361
- // "conda update -y --all",// -vvv --debug",
362
-
363
-
364
- // "python -m pip install --upgrade pip setuptools wheel",
365
- // "python -m ensurepip --upgrade",
366
- // "conda update -y conda",
367
- // "conda update -y --all",
294
+ `conda install -y --override-channels -c conda-forge ${condaPackages.join(" ")} ${mods}`.trim(),
368
295
  ]
369
- //if (this.kernel.platform === "win32" || this.kernel.platform === "darwin") {
370
- // cmds.push("conda install -y conda-libmamba-solver=24.7.0 conda=24.7.1 --freeze-installed")
371
- //}
372
296
  await this.kernel.bin.exec({
373
297
  message: cmds,
374
298
  env: {
375
299
  PIP_REQUIRE_VIRTUALENV: "false"
376
300
  }
377
- // conda: {
378
- // name: "base",
379
- // activate: "minimal"
380
- // }
381
- // [
382
- // (this.kernel.platform === 'win32' ? 'conda_hook' : `eval "$(conda shell.bash hook)"`),
383
- // (this.platform === 'win32' ? `activate base` : `conda activate base`),
384
- /*
385
- `conda config --file ${this.kernel.bin.path('miniconda', 'condarc')} --remove channels conda-forge`,
386
- `conda config --file ${this.kernel.bin.path('miniconda', 'condarc')} --remove channels defaults`,
387
- `conda config --file ${this.kernel.bin.path('miniconda', 'condarc')} --prepend channels defaults`,
388
- `conda config --file ${this.kernel.bin.path('miniconda', 'condarc')} --prepend channels conda-forge`,
389
- `conda config --file ${this.kernel.bin.path('miniconda', 'condarc')} --add create_default_packages python=3.10`,
390
- */
391
- //"conda update -y conda",
392
- //"conda update -n base -c conda-forge -c defaults conda",
393
-
394
-
395
- //"conda install conda=24.5.0",
396
- // "conda clean -y --index-cache",
397
- // "conda update -y --all",
398
- // "conda install conda=24.9.0"
399
-
400
-
401
- // handling the conda-libmamba-solver bug here: https://github.com/conda/conda-libmamba-solver/issues/283
402
-
403
-
404
- // "conda remove -y libarchive",
405
- // "conda install -y -c conda-forge libarchive",
406
- // "conda install -y -c conda-forge pip brotli brotlipy",
407
- // "conda install -y -c conda-forge libsqlite --force-reinstall",
408
- // "conda install conda"
409
-
410
-
411
- //"conda install -y -c conda-forge pip brotli brotlipy",
412
- // "conda update --all",
413
- // "conda update -y --all",
414
- // ]
415
301
  }, (stream) => {
416
302
  ondata(stream)
417
303
  })
418
304
  if (this.kernel.platform === "win32") {
419
305
  // copy python.exe to python3.exe so you can run with both python3 and python
420
306
  await fs.promises.copyFile(
421
- this.kernel.bin.path("miniconda", "python.exe"),
422
- this.kernel.bin.path("miniconda", "python3.exe"),
307
+ this.kernel.bin.path(CONDA_ROOT_DIR, "python.exe"),
308
+ this.kernel.bin.path(CONDA_ROOT_DIR, "python3.exe"),
423
309
  )
424
310
  }
425
311
  await this.ensureSslCertDirOverride()
312
+ await this.writeRuntimeStamp()
313
+ await this.ensureCompatibilityAlias()
426
314
  ondata({ raw: `Install finished\r\n` })
427
315
  await this.kernel.bin.rm(installer, ondata)
428
316
  }
317
+ async removeInstallPath(target) {
318
+ try {
319
+ const stat = await fs.promises.lstat(target).catch((error) => {
320
+ if (error && error.code === "ENOENT") {
321
+ return null
322
+ }
323
+ throw error
324
+ })
325
+ if (!stat) {
326
+ return
327
+ }
328
+ if (stat.isSymbolicLink()) {
329
+ await fs.promises.rm(target, { force: true })
330
+ return
331
+ }
332
+ await fs.promises.rm(target, {
333
+ recursive: true,
334
+ force: true,
335
+ maxRetries: 5,
336
+ retryDelay: 250,
337
+ })
338
+ } catch (error) {
339
+ const reason = error && (error.code || error.message) ? error.code || error.message : String(error)
340
+ throw new Error([
341
+ `Pinokio needs to replace the Conda runtime at ${target}, but it could not delete that folder.`,
342
+ "Close Pinokio and any terminals or editors using Pinokio, delete that folder manually, then reopen Pinokio.",
343
+ `Original error: ${reason}`,
344
+ ].join("\n"))
345
+ }
346
+ }
347
+ async ensureCompatibilityAlias() {
348
+ const target = this.kernel.bin.path(CONDA_ROOT_DIR)
349
+ const alias = this.kernel.bin.path(CONDA_COMPAT_ROOT_DIR)
350
+ const targetExists = await fs.promises.access(target).then(() => true).catch(() => false)
351
+ if (!targetExists) {
352
+ return
353
+ }
354
+ const aliasExists = await fs.promises.lstat(alias).then(() => true).catch(() => false)
355
+ if (aliasExists) {
356
+ return
357
+ }
358
+ try {
359
+ await fs.promises.symlink(target, alias, this.kernel.platform === "win32" ? "junction" : "dir")
360
+ } catch (error) {
361
+ console.warn("Could not create Conda compatibility alias", error && error.message ? error.message : error)
362
+ }
363
+ }
429
364
  async exists(pattern) {
430
365
  let paths = this.paths[this.kernel.platform]
431
366
  for(let p of paths) {
432
- //let e = await this.kernel.bin.exists(p + "/" + name)
433
367
  const found = await glob(pattern, {
434
368
  cwd: this.kernel.bin.path(p)
435
369
  })
@@ -441,17 +375,22 @@ report_errors: false`)
441
375
  }
442
376
 
443
377
  async installed() {
444
- let e
445
378
  for(let p of this.paths[this.kernel.platform]) {
446
379
  let e = await this.kernel.bin.exists(p)
447
- if (e && this.kernel.bin.correct_conda) return true
380
+ 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
+ return true
386
+ }
448
387
  }
449
388
  return false
450
389
  }
451
390
 
452
- uninstall(req, ondata) {
453
- const install_path = this.kernel.bin.path("miniconda")
454
- return this.kernel.bin.rm(install_path, ondata)
391
+ async uninstall(req, ondata) {
392
+ await this.kernel.bin.rm(CONDA_COMPAT_ROOT_DIR, ondata)
393
+ return this.kernel.bin.rm(CONDA_ROOT_DIR, ondata)
455
394
  }
456
395
 
457
396
  onstart() {