pinokiod 6.0.90 → 6.0.92
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/brew.js +51 -31
- package/kernel/bin/index.js +6 -11
- package/kernel/bin/xcode-tools.js +43 -8
- package/kernel/index.js +0 -3
- package/package.json +1 -1
- package/server/index.js +3 -1
- package/server/views/install.ejs +8 -1
- package/server/views/terminals.ejs +27 -16
package/kernel/bin/brew.js
CHANGED
|
@@ -5,56 +5,66 @@ const { detectCommandLineTools } = require('./xcode-tools')
|
|
|
5
5
|
class Brew {
|
|
6
6
|
description = "Wait for an install pop-up, then approve."
|
|
7
7
|
async install(req, ondata) {
|
|
8
|
-
const installer_url = "https://github.com/cocktailpeanut/bin/releases/download/homebrew/homebrew.zip"
|
|
9
|
-
//const installer_url = "https://github.com/Homebrew/brew/tarball/master"
|
|
10
|
-
const installer = "Homebrew.zip"
|
|
11
|
-
|
|
12
|
-
ondata({ raw: `downloading installer: ${installer_url}...\r\n` })
|
|
13
|
-
await this.kernel.bin.download(installer_url, installer, ondata)
|
|
14
|
-
console.log("## DOWNLOADED")
|
|
15
|
-
|
|
16
|
-
console.log("homebrewpath", this.kernel.bin.path("homebrew"))
|
|
17
|
-
await this.kernel.bin.rm("homebrew", ondata)
|
|
18
|
-
|
|
19
|
-
// 2. run the script
|
|
20
|
-
ondata({ raw: `unzipping installer: ${installer}...\r\n` })
|
|
21
|
-
await this.kernel.bin.unzip("Homebrew.zip", this.kernel.bin.path(), null, ondata)
|
|
22
|
-
await this.kernel.bin.rm("Homebrew.zip", ondata)
|
|
23
|
-
|
|
24
8
|
if (this.kernel.platform === "darwin") {
|
|
25
9
|
const checkingMsg = "> checking xcode command line tools...\r\n"
|
|
26
10
|
console.log(checkingMsg)
|
|
27
11
|
ondata({ raw: checkingMsg })
|
|
28
12
|
|
|
29
|
-
const cltStatus = await detectCommandLineTools(
|
|
30
|
-
exec: (params) => this.kernel.bin.exec(params, () => {})
|
|
31
|
-
})
|
|
13
|
+
const cltStatus = await detectCommandLineTools()
|
|
32
14
|
|
|
33
15
|
if (cltStatus.valid) {
|
|
34
16
|
const msg = `> command line tools detected at ${cltStatus.path} (pkg ${cltStatus.pkgVersion}, xcode-select ${cltStatus.xcodeSelectVersion}). skipping...\r\n`
|
|
35
17
|
console.log(msg)
|
|
36
18
|
ondata({ raw: msg })
|
|
19
|
+
} else if (needsManualXcodeAction(cltStatus.reason)) {
|
|
20
|
+
const instruction = manualXcodeActionMessage(cltStatus.reason)
|
|
21
|
+
const msg = `> ${instruction}\r\n`
|
|
22
|
+
console.log(msg)
|
|
23
|
+
ondata({ raw: msg })
|
|
24
|
+
ondata({
|
|
25
|
+
blocker: true,
|
|
26
|
+
html: `<b><i class="fa-solid fa-circle-exclamation"></i> Xcode action required</b><div style="padding-top:8px">${instruction}</div>`
|
|
27
|
+
}, "notify3")
|
|
28
|
+
throw new Error(`__PINOKIO_BLOCKER__ ${instruction}`)
|
|
37
29
|
} else {
|
|
38
30
|
const msg = `> ${cltStatus.reason || "command line tools not installed yet."} install the latest xcode build tools...\r\n`
|
|
39
31
|
console.log(msg)
|
|
40
32
|
ondata({ raw: msg })
|
|
41
|
-
await this._install(req, ondata)
|
|
33
|
+
await this._install(req, ondata, shouldRemoveCommandLineTools(cltStatus.reason))
|
|
42
34
|
}
|
|
43
35
|
}
|
|
36
|
+
|
|
37
|
+
const installer_url = "https://github.com/cocktailpeanut/bin/releases/download/homebrew/homebrew.zip"
|
|
38
|
+
//const installer_url = "https://github.com/Homebrew/brew/tarball/master"
|
|
39
|
+
const installer = "Homebrew.zip"
|
|
40
|
+
|
|
41
|
+
ondata({ raw: `downloading installer: ${installer_url}...\r\n` })
|
|
42
|
+
await this.kernel.bin.download(installer_url, installer, ondata)
|
|
43
|
+
console.log("## DOWNLOADED")
|
|
44
|
+
|
|
45
|
+
console.log("homebrewpath", this.kernel.bin.path("homebrew"))
|
|
46
|
+
await this.kernel.bin.rm("homebrew", ondata)
|
|
47
|
+
|
|
48
|
+
// 2. run the script
|
|
49
|
+
ondata({ raw: `unzipping installer: ${installer}...\r\n` })
|
|
50
|
+
await this.kernel.bin.unzip("Homebrew.zip", this.kernel.bin.path(), null, ondata)
|
|
51
|
+
await this.kernel.bin.rm("Homebrew.zip", ondata)
|
|
44
52
|
//
|
|
45
53
|
ondata({ raw: "installing gettext\r\n" })
|
|
46
54
|
await this.kernel.bin.exec({ message: "brew install gettext --force-bottle", conda: { skip: true } }, (stream) => { ondata(stream) })
|
|
47
55
|
//
|
|
48
56
|
ondata({ raw: `Install finished\r\n` })
|
|
49
57
|
}
|
|
50
|
-
async _install(req, ondata) {
|
|
58
|
+
async _install(req, ondata, removeExisting = false) {
|
|
51
59
|
// command line tools installed
|
|
52
60
|
const msg = "> installing the latest xcode build tools...\r\n"
|
|
53
61
|
console.log(msg)
|
|
54
62
|
ondata({ raw: msg })
|
|
55
63
|
// not installed or not installed properly
|
|
56
64
|
// install xcode build tools
|
|
57
|
-
|
|
65
|
+
if (removeExisting) {
|
|
66
|
+
await this.kernel.bin.exec({ sudo: true, conda: { skip: true }, message: "rm -rf /Library/Developer/CommandLineTools" }, (stream) => { ondata(stream) })
|
|
67
|
+
}
|
|
58
68
|
let sh_path = path.resolve(this.kernel.homedir, "xcode.sh")
|
|
59
69
|
let src_path = path.resolve(__dirname, "xcode.sh")
|
|
60
70
|
console.log({ sh_path, src_path })
|
|
@@ -68,16 +78,10 @@ class Brew {
|
|
|
68
78
|
}
|
|
69
79
|
|
|
70
80
|
async installed() {
|
|
81
|
+
const homebrewExists = await this.kernel.bin.exists("homebrew")
|
|
82
|
+
const cltStatus = homebrewExists ? await detectCommandLineTools() : { valid: false }
|
|
83
|
+
this.kernel.bin.brew_installed = homebrewExists && cltStatus.valid
|
|
71
84
|
return this.kernel.bin.brew_installed
|
|
72
|
-
/*
|
|
73
|
-
let e = await this.kernel.bin.exists("homebrew")
|
|
74
|
-
|
|
75
|
-
let { stdout }= await this.kernel.bin.exec({ message: "xcode-select -p" }, (stream) => { })
|
|
76
|
-
let e2 = /(.*Library.*Developer.*CommandLineTools.*|.*Xcode.*Developer.*)/gi.test(stdout)
|
|
77
|
-
console.log({ e, e2, stdout })
|
|
78
|
-
|
|
79
|
-
return e && e2
|
|
80
|
-
*/
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
uninstall(req, ondata) {
|
|
@@ -96,4 +100,20 @@ class Brew {
|
|
|
96
100
|
}
|
|
97
101
|
}
|
|
98
102
|
}
|
|
103
|
+
|
|
104
|
+
function needsManualXcodeAction(reason) {
|
|
105
|
+
return reason === "xcode license not accepted" || reason === "xcode first launch is incomplete"
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function manualXcodeActionMessage(reason) {
|
|
109
|
+
if (reason === "xcode license not accepted") {
|
|
110
|
+
return "xcode license not accepted. open Xcode once and accept the license, then retry"
|
|
111
|
+
}
|
|
112
|
+
return "xcode first launch is incomplete. open Xcode once to finish setup, then retry"
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function shouldRemoveCommandLineTools(reason) {
|
|
116
|
+
return typeof reason === "string" && reason.startsWith("command line tools version ") && reason.includes(" is below required ")
|
|
117
|
+
}
|
|
118
|
+
|
|
99
119
|
module.exports = Brew
|
package/kernel/bin/index.js
CHANGED
|
@@ -21,7 +21,6 @@ const LLVM = require('./llvm')
|
|
|
21
21
|
const VS = require("./vs")
|
|
22
22
|
const Cuda = require("./cuda")
|
|
23
23
|
const Torch = require("./torch")
|
|
24
|
-
const { detectCommandLineTools } = require('./xcode-tools')
|
|
25
24
|
const { buildCondaListFromMeta } = require('./conda-meta')
|
|
26
25
|
const { glob } = require('glob')
|
|
27
26
|
const fakeUa = require('fake-useragent');
|
|
@@ -460,14 +459,7 @@ class Bin {
|
|
|
460
459
|
this.installed.brew = new Set(brew)
|
|
461
460
|
|
|
462
461
|
|
|
463
|
-
|
|
464
|
-
let e = await this.kernel.bin.exists("homebrew")
|
|
465
|
-
const cltStatus = await detectCommandLineTools({
|
|
466
|
-
exec: (params) => this.exec(params, () => {})
|
|
467
|
-
})
|
|
468
|
-
console.log({ cltStatus })
|
|
469
|
-
this.brew_installed = e && cltStatus.valid
|
|
470
|
-
|
|
462
|
+
this.brew_installed = await this.kernel.bin.exists("homebrew")
|
|
471
463
|
console.log("brew_installed", this.brew_installed)
|
|
472
464
|
|
|
473
465
|
}
|
|
@@ -1036,7 +1028,8 @@ class Bin {
|
|
|
1036
1028
|
let r = requirements[i]
|
|
1037
1029
|
let fingerprint = JSON.stringify(r)
|
|
1038
1030
|
let installed
|
|
1039
|
-
|
|
1031
|
+
const canUseCache = r.name !== "brew" || r.type
|
|
1032
|
+
if (canUseCache && fingerprint in this.requirements_cache) {
|
|
1040
1033
|
let relevant = this.relevant(r)
|
|
1041
1034
|
requirements[i].relevant = relevant
|
|
1042
1035
|
if (relevant) {
|
|
@@ -1063,7 +1056,9 @@ class Bin {
|
|
|
1063
1056
|
requirements[i].dependencies = dependencies
|
|
1064
1057
|
}
|
|
1065
1058
|
installed = await this.check_installed(r, dependencies)
|
|
1066
|
-
|
|
1059
|
+
if (canUseCache) {
|
|
1060
|
+
this.requirements_cache[fingerprint] = installed
|
|
1061
|
+
}
|
|
1067
1062
|
//if (installed) {
|
|
1068
1063
|
// // cache if true
|
|
1069
1064
|
// this.requirements_cache[fingerprint] = true
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const fs = require('fs')
|
|
2
|
+
const { execFile } = require('child_process')
|
|
2
3
|
const semver = require('semver')
|
|
3
4
|
|
|
4
5
|
const MIN_CLT_VERSION = '13.0'
|
|
@@ -13,19 +14,17 @@ const PACKAGE_MATCHERS = [
|
|
|
13
14
|
/^com\.apple\.pkg\.Xcode$/
|
|
14
15
|
]
|
|
15
16
|
|
|
16
|
-
async function detectCommandLineTools({ exec }) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const run = (message) => exec({ message, conda: { skip: true } })
|
|
17
|
+
async function detectCommandLineTools({ exec } = {}) {
|
|
18
|
+
const run = (typeof exec === 'function')
|
|
19
|
+
? (message) => exec({ message, conda: { skip: true } })
|
|
20
|
+
: (message) => execCommand(message)
|
|
22
21
|
|
|
23
22
|
let selectResult
|
|
24
23
|
try {
|
|
25
24
|
selectResult = await run('xcode-select -p')
|
|
26
25
|
} catch (err) {
|
|
27
26
|
console.log('[CLT] xcode-select -p failed', err)
|
|
28
|
-
return
|
|
27
|
+
return invalidFromError('xcode-select -p', err, 'xcode-select -p failed')
|
|
29
28
|
}
|
|
30
29
|
|
|
31
30
|
const developerPath = (selectResult && selectResult.stdout ? selectResult.stdout : '')
|
|
@@ -56,7 +55,7 @@ async function detectCommandLineTools({ exec }) {
|
|
|
56
55
|
clangResult = await run('xcrun --find clang')
|
|
57
56
|
} catch (err) {
|
|
58
57
|
console.log('[CLT] xcrun --find clang failed', err)
|
|
59
|
-
return
|
|
58
|
+
return invalidFromError('xcrun --find clang', err, 'unable to locate clang via xcrun')
|
|
60
59
|
}
|
|
61
60
|
|
|
62
61
|
const clangStdout = clangResult && clangResult.stdout ? clangResult.stdout : ''
|
|
@@ -109,6 +108,42 @@ async function detectCommandLineTools({ exec }) {
|
|
|
109
108
|
return status
|
|
110
109
|
}
|
|
111
110
|
|
|
111
|
+
async function execCommand(message) {
|
|
112
|
+
const tokens = String(message || '').trim().split(/\s+/).filter(Boolean)
|
|
113
|
+
const file = tokens.shift()
|
|
114
|
+
if (!file) {
|
|
115
|
+
throw new Error('missing command')
|
|
116
|
+
}
|
|
117
|
+
return new Promise((resolve, reject) => {
|
|
118
|
+
execFile(file, tokens, {
|
|
119
|
+
timeout: 8000,
|
|
120
|
+
maxBuffer: 1024 * 1024,
|
|
121
|
+
}, (error, stdout, stderr) => {
|
|
122
|
+
if (error) {
|
|
123
|
+
error.stdout = stdout
|
|
124
|
+
error.stderr = stderr
|
|
125
|
+
reject(error)
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
resolve({ stdout })
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function invalidFromError(command, error, fallbackReason) {
|
|
134
|
+
const stderr = error && typeof error.stderr === 'string' ? error.stderr : ''
|
|
135
|
+
if (error && error.killed && error.signal === 'SIGTERM') {
|
|
136
|
+
return { valid: false, reason: `${command} timed out` }
|
|
137
|
+
}
|
|
138
|
+
if (/license agreements/i.test(stderr)) {
|
|
139
|
+
return { valid: false, reason: 'xcode license not accepted' }
|
|
140
|
+
}
|
|
141
|
+
if (/runfirstlaunch|first launch/i.test(stderr)) {
|
|
142
|
+
return { valid: false, reason: 'xcode first launch is incomplete' }
|
|
143
|
+
}
|
|
144
|
+
return { valid: false, reason: fallbackReason }
|
|
145
|
+
}
|
|
146
|
+
|
|
112
147
|
async function pkgInfoFor(run, pkgId) {
|
|
113
148
|
try {
|
|
114
149
|
const result = await run(`pkgutil --pkg-info=${pkgId}`)
|
package/kernel/index.js
CHANGED
|
@@ -1063,9 +1063,6 @@ class Kernel {
|
|
|
1063
1063
|
console.warn("Git init error:", err && err.message ? err.message : err)
|
|
1064
1064
|
})
|
|
1065
1065
|
this.shell.init().then(async () => {
|
|
1066
|
-
this.bin.check({
|
|
1067
|
-
bin: this.bin.preset("dev"),
|
|
1068
|
-
})
|
|
1069
1066
|
if (this.envs) {
|
|
1070
1067
|
this.template.update({
|
|
1071
1068
|
env: this.envs,
|
package/package.json
CHANGED
package/server/index.js
CHANGED
|
@@ -5062,7 +5062,9 @@ class Server {
|
|
|
5062
5062
|
|
|
5063
5063
|
|
|
5064
5064
|
await this.kernel.init({ port: this.port})
|
|
5065
|
-
|
|
5065
|
+
if (this.kernel.homedir) {
|
|
5066
|
+
await Environment.init({}, this.kernel)
|
|
5067
|
+
}
|
|
5066
5068
|
this.kernel.server_port = this.port
|
|
5067
5069
|
this.kernel.peer.start(this.kernel)
|
|
5068
5070
|
|
package/server/views/install.ejs
CHANGED
|
@@ -260,6 +260,9 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
260
260
|
} else if (packet.type === "result") {
|
|
261
261
|
resolve()
|
|
262
262
|
} else if (packet.type === "error") {
|
|
263
|
+
if (typeof packet.data === "string" && packet.data.includes("__PINOKIO_BLOCKER__")) {
|
|
264
|
+
return
|
|
265
|
+
}
|
|
263
266
|
//term.write("\r\n" + packet.data + "\r\n")
|
|
264
267
|
ModalInput({
|
|
265
268
|
title: "Error",
|
|
@@ -279,12 +282,16 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
279
282
|
document.querySelector("#status-screen").innerHTML = packet.data.html
|
|
280
283
|
let audio = new Audio("/chime.mp3")
|
|
281
284
|
audio.play()
|
|
282
|
-
ModalInput({
|
|
285
|
+
await ModalInput({
|
|
283
286
|
title: "Notice",
|
|
284
287
|
type: "modal",
|
|
285
288
|
description: packet.data.html,
|
|
286
289
|
confirm: "OK",
|
|
287
290
|
})
|
|
291
|
+
if (packet.data.blocker) {
|
|
292
|
+
location.href = document.querySelector("#callback").value
|
|
293
|
+
return
|
|
294
|
+
}
|
|
288
295
|
}
|
|
289
296
|
} else if (packet.type === "notify2") {
|
|
290
297
|
console.log("HTML", packet.data)
|
|
@@ -8232,11 +8232,28 @@ body.dark .swal2-popup.pinokio-diff-modal .pinokio-modal-footer--commit .pinokio
|
|
|
8232
8232
|
if (!column) {
|
|
8233
8233
|
return
|
|
8234
8234
|
}
|
|
8235
|
-
|
|
8236
|
-
if (!terminalId) {
|
|
8235
|
+
if (type === "terminal-input") {
|
|
8237
8236
|
return
|
|
8238
8237
|
}
|
|
8239
|
-
if (type === "
|
|
8238
|
+
if (type === "idle") {
|
|
8239
|
+
const workspacePath = normalizeIndex(column.dataset.sessionCwd || "")
|
|
8240
|
+
if (workspacePath) {
|
|
8241
|
+
fetchWorkspaceGitStatus(workspacePath, { force: true }).catch(() => {
|
|
8242
|
+
})
|
|
8243
|
+
}
|
|
8244
|
+
refreshSessionItems({
|
|
8245
|
+
sync: true,
|
|
8246
|
+
query: currentSessionQuery,
|
|
8247
|
+
workspaceKey: workspaceViewState.mode === "sessions" ? workspaceViewState.key : ""
|
|
8248
|
+
}).then((loaded) => {
|
|
8249
|
+
if (loaded || hasAttemptedSessionLoad) {
|
|
8250
|
+
refreshChooserRows({ autoLoad: false })
|
|
8251
|
+
}
|
|
8252
|
+
})
|
|
8253
|
+
return
|
|
8254
|
+
}
|
|
8255
|
+
const terminalId = normalizeTerminalId(column.dataset.sessionTerminalId || "")
|
|
8256
|
+
if (!terminalId) {
|
|
8240
8257
|
return
|
|
8241
8258
|
}
|
|
8242
8259
|
if (type === "stream" || type === "start") {
|
|
@@ -8261,18 +8278,6 @@ body.dark .swal2-popup.pinokio-diff-modal .pinokio-modal-footer--commit .pinokio
|
|
|
8261
8278
|
}
|
|
8262
8279
|
return
|
|
8263
8280
|
}
|
|
8264
|
-
if (type === "idle") {
|
|
8265
|
-
void refreshSessionItems({
|
|
8266
|
-
sync: true,
|
|
8267
|
-
query: currentSessionQuery,
|
|
8268
|
-
workspaceKey: workspaceViewState.mode === "sessions" ? workspaceViewState.key : ""
|
|
8269
|
-
}).then((loaded) => {
|
|
8270
|
-
if (loaded || hasAttemptedSessionLoad) {
|
|
8271
|
-
refreshChooserRows({ autoLoad: false })
|
|
8272
|
-
}
|
|
8273
|
-
})
|
|
8274
|
-
return
|
|
8275
|
-
}
|
|
8276
8281
|
if (type === "disconnect") {
|
|
8277
8282
|
const removedTemporary = removeTemporarySessionByTerminalId(terminalId)
|
|
8278
8283
|
if (removedTemporary) {
|
|
@@ -9689,7 +9694,9 @@ body.dark .swal2-popup.pinokio-diff-modal .pinokio-modal-footer--commit .pinokio
|
|
|
9689
9694
|
setColumnLayout()
|
|
9690
9695
|
ensureLayout()
|
|
9691
9696
|
refreshChooserRows()
|
|
9692
|
-
|
|
9697
|
+
fetchWorkspaceGitStatus(targetWorkspaceKey, { force: true }).catch(() => {
|
|
9698
|
+
})
|
|
9699
|
+
refreshSessionItems({
|
|
9693
9700
|
query: "",
|
|
9694
9701
|
workspaceKey: targetWorkspaceKey
|
|
9695
9702
|
}).then((loaded) => {
|
|
@@ -10020,6 +10027,10 @@ body.dark .swal2-popup.pinokio-diff-modal .pinokio-modal-footer--commit .pinokio
|
|
|
10020
10027
|
)
|
|
10021
10028
|
topSessionRefreshButton.disabled = true
|
|
10022
10029
|
try {
|
|
10030
|
+
if (workspaceKey) {
|
|
10031
|
+
fetchWorkspaceGitStatus(workspaceKey, { force: true }).catch(() => {
|
|
10032
|
+
})
|
|
10033
|
+
}
|
|
10023
10034
|
const refreshed = await refreshSessionItems({
|
|
10024
10035
|
sync: true,
|
|
10025
10036
|
limit: getCurrentSessionRefreshLimit(),
|