pinokiod 8.0.8 → 8.0.10
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 +17 -17
- package/kernel/path_removal.js +150 -0
- package/kernel/windows_restart_manager.js +153 -0
- package/package.json +1 -1
- package/server/index.js +39 -4
- package/server/public/common.js +190 -0
- package/server/public/style.css +65 -0
- package/server/views/app.ejs +2 -4
- package/server/views/download.ejs +5 -5
- package/server/views/editor.ejs +5 -5
- package/server/views/env_editor.ejs +4 -2
- package/server/views/file_explorer.ejs +2 -4
- package/server/views/index.ejs +2 -4
- package/server/views/install.ejs +25 -0
- package/server/views/net.ejs +2 -4
- package/server/views/settings.ejs +10 -10
- package/server/views/setup.ejs +5 -5
- package/server/views/terminal.ejs +5 -5
- package/test/conda-bin.test.js +11 -11
- package/test/fixtures/hold-windows-dll.js +21 -0
- package/test/path-removal-ui.test.js +316 -0
- package/test/path-removal.test.js +189 -0
- package/test/windows-path-removal.integration.test.js +78 -0
package/server/public/style.css
CHANGED
|
@@ -6973,3 +6973,68 @@ body.dark .swal2-popup.swal2-modal:not(.loader-popup):not(.pinokio-download-moda
|
|
|
6973
6973
|
width: 100%;
|
|
6974
6974
|
}
|
|
6975
6975
|
}
|
|
6976
|
+
|
|
6977
|
+
.pinokio-path-blocker > p {
|
|
6978
|
+
margin: 0 0 14px;
|
|
6979
|
+
}
|
|
6980
|
+
|
|
6981
|
+
.pinokio-path-blocker-list {
|
|
6982
|
+
margin: 0 0 14px;
|
|
6983
|
+
padding: 0;
|
|
6984
|
+
list-style: none;
|
|
6985
|
+
}
|
|
6986
|
+
|
|
6987
|
+
.pinokio-path-blocker-item {
|
|
6988
|
+
display: flex;
|
|
6989
|
+
align-items: baseline;
|
|
6990
|
+
justify-content: space-between;
|
|
6991
|
+
gap: 16px;
|
|
6992
|
+
padding: 8px 0;
|
|
6993
|
+
border-bottom: 1px solid rgba(127, 127, 127, 0.18);
|
|
6994
|
+
}
|
|
6995
|
+
|
|
6996
|
+
.pinokio-path-blocker-name {
|
|
6997
|
+
font-weight: 600;
|
|
6998
|
+
}
|
|
6999
|
+
|
|
7000
|
+
.pinokio-path-blocker-detail {
|
|
7001
|
+
font-size: 12px;
|
|
7002
|
+
overflow-wrap: anywhere;
|
|
7003
|
+
text-align: right;
|
|
7004
|
+
}
|
|
7005
|
+
|
|
7006
|
+
.pinokio-path-blocker-files {
|
|
7007
|
+
margin: 0 0 14px;
|
|
7008
|
+
}
|
|
7009
|
+
|
|
7010
|
+
.pinokio-path-blocker-files summary {
|
|
7011
|
+
cursor: pointer;
|
|
7012
|
+
}
|
|
7013
|
+
|
|
7014
|
+
.pinokio-path-blocker-files div {
|
|
7015
|
+
display: grid;
|
|
7016
|
+
gap: 6px;
|
|
7017
|
+
margin-top: 8px;
|
|
7018
|
+
}
|
|
7019
|
+
|
|
7020
|
+
.pinokio-path-blocker-files code {
|
|
7021
|
+
overflow-wrap: anywhere;
|
|
7022
|
+
white-space: normal;
|
|
7023
|
+
}
|
|
7024
|
+
|
|
7025
|
+
.pinokio-path-blocker-wait {
|
|
7026
|
+
display: flex;
|
|
7027
|
+
align-items: center;
|
|
7028
|
+
gap: 8px;
|
|
7029
|
+
}
|
|
7030
|
+
|
|
7031
|
+
@media (max-width: 560px) {
|
|
7032
|
+
.pinokio-path-blocker-item {
|
|
7033
|
+
display: grid;
|
|
7034
|
+
gap: 2px;
|
|
7035
|
+
}
|
|
7036
|
+
|
|
7037
|
+
.pinokio-path-blocker-detail {
|
|
7038
|
+
text-align: left;
|
|
7039
|
+
}
|
|
7040
|
+
}
|
package/server/views/app.ejs
CHANGED
|
@@ -11866,15 +11866,13 @@ const rerenderMenuSection = (container, html) => {
|
|
|
11866
11866
|
actions: "hidden"
|
|
11867
11867
|
}
|
|
11868
11868
|
});
|
|
11869
|
-
let res = await fetch("/pinokio/delete", {
|
|
11869
|
+
let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
11870
11870
|
method: "post",
|
|
11871
11871
|
headers: {
|
|
11872
11872
|
"Content-Type": "application/json"
|
|
11873
11873
|
},
|
|
11874
11874
|
body: JSON.stringify({ name })
|
|
11875
|
-
})
|
|
11876
|
-
return res.json()
|
|
11877
|
-
})
|
|
11875
|
+
}))
|
|
11878
11876
|
console.log("res", res)
|
|
11879
11877
|
Swal.close()
|
|
11880
11878
|
if (res) {
|
|
@@ -231,18 +231,18 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
231
231
|
if (proceed) {
|
|
232
232
|
document.querySelector(".reset-bin-loading").classList.remove("hidden")
|
|
233
233
|
document.querySelector("#del-bin").classList.add("hidden")
|
|
234
|
-
let res = await fetch("/pinokio/delete", {
|
|
234
|
+
let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
235
235
|
method: "post",
|
|
236
236
|
headers: {
|
|
237
237
|
"Content-Type": "application/json"
|
|
238
238
|
},
|
|
239
239
|
body: JSON.stringify({ type: "bin" })
|
|
240
|
-
})
|
|
241
|
-
return res.json()
|
|
242
|
-
})
|
|
240
|
+
}))
|
|
243
241
|
console.log(res)
|
|
244
242
|
document.querySelector(".reset-bin-loading").classList.add("hidden")
|
|
245
|
-
if (res.
|
|
243
|
+
if (res.cancelled) {
|
|
244
|
+
document.querySelector("#del-bin").classList.remove("hidden")
|
|
245
|
+
} else if (res.error) {
|
|
246
246
|
alert(res.error)
|
|
247
247
|
} else {
|
|
248
248
|
//location.href = location.href
|
package/server/views/editor.ejs
CHANGED
|
@@ -940,18 +940,18 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
940
940
|
if (proceed) {
|
|
941
941
|
document.querySelector(".reset-bin-loading").classList.remove("hidden")
|
|
942
942
|
document.querySelector("#del-bin").classList.add("hidden")
|
|
943
|
-
let res = await fetch("/pinokio/delete", {
|
|
943
|
+
let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
944
944
|
method: "post",
|
|
945
945
|
headers: {
|
|
946
946
|
"Content-Type": "application/json"
|
|
947
947
|
},
|
|
948
948
|
body: JSON.stringify({ type: "bin" })
|
|
949
|
-
})
|
|
950
|
-
return res.json()
|
|
951
|
-
})
|
|
949
|
+
}))
|
|
952
950
|
console.log(res)
|
|
953
951
|
document.querySelector(".reset-bin-loading").classList.add("hidden")
|
|
954
|
-
if (res.
|
|
952
|
+
if (res.cancelled) {
|
|
953
|
+
document.querySelector("#del-bin").classList.remove("hidden")
|
|
954
|
+
} else if (res.error) {
|
|
955
955
|
alert(res.error)
|
|
956
956
|
} else {
|
|
957
957
|
document.querySelector("#install-form").submit()
|
|
@@ -447,16 +447,18 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
447
447
|
}
|
|
448
448
|
})
|
|
449
449
|
try {
|
|
450
|
-
const res = await fetch("/pinokio/delete", {
|
|
450
|
+
const res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
451
451
|
method: "post",
|
|
452
452
|
headers: {
|
|
453
453
|
"Content-Type": "application/json"
|
|
454
454
|
},
|
|
455
455
|
body: JSON.stringify({ name: projectName })
|
|
456
|
-
})
|
|
456
|
+
}))
|
|
457
457
|
Swal.close()
|
|
458
458
|
if (res && res.success) {
|
|
459
459
|
navigateHome()
|
|
460
|
+
} else if (res && res.cancelled) {
|
|
461
|
+
return
|
|
460
462
|
} else if (res && res.error) {
|
|
461
463
|
alert(res.error)
|
|
462
464
|
} else {
|
|
@@ -636,15 +636,13 @@ document.addEventListener("click", async (e) => {
|
|
|
636
636
|
actions: "hidden"
|
|
637
637
|
}
|
|
638
638
|
});
|
|
639
|
-
let res = await fetch("/pinokio/delete", {
|
|
639
|
+
let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
640
640
|
method: "post",
|
|
641
641
|
headers: {
|
|
642
642
|
"Content-Type": "application/json"
|
|
643
643
|
},
|
|
644
644
|
body: JSON.stringify({ name })
|
|
645
|
-
})
|
|
646
|
-
return res.json()
|
|
647
|
-
})
|
|
645
|
+
}))
|
|
648
646
|
console.log("res", res)
|
|
649
647
|
Swal.close()
|
|
650
648
|
if (res) {
|
package/server/views/index.ejs
CHANGED
|
@@ -4031,15 +4031,13 @@ document.addEventListener("click", async (e) => {
|
|
|
4031
4031
|
actions: "hidden"
|
|
4032
4032
|
}
|
|
4033
4033
|
});
|
|
4034
|
-
let res = await fetch("/pinokio/delete", {
|
|
4034
|
+
let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
4035
4035
|
method: "post",
|
|
4036
4036
|
headers: {
|
|
4037
4037
|
"Content-Type": "application/json"
|
|
4038
4038
|
},
|
|
4039
4039
|
body: JSON.stringify({ name })
|
|
4040
|
-
})
|
|
4041
|
-
return res.json()
|
|
4042
|
-
})
|
|
4040
|
+
}))
|
|
4043
4041
|
console.log("res", res)
|
|
4044
4042
|
Swal.close()
|
|
4045
4043
|
if (res) {
|
package/server/views/install.ejs
CHANGED
|
@@ -851,6 +851,31 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
851
851
|
socket.close()
|
|
852
852
|
} else if (packet.type === "result") {
|
|
853
853
|
resolve()
|
|
854
|
+
} else if (packet.type === "path.remove.blocked") {
|
|
855
|
+
const result = await PinokioPathRemoval.show({
|
|
856
|
+
details: packet.data,
|
|
857
|
+
retry: async () => {
|
|
858
|
+
const response = await fetch("/pinokio/delete", {
|
|
859
|
+
method: "post",
|
|
860
|
+
headers: {
|
|
861
|
+
"Content-Type": "application/json"
|
|
862
|
+
},
|
|
863
|
+
body: JSON.stringify({ type: "conda-runtime" })
|
|
864
|
+
})
|
|
865
|
+
const payload = await response.json()
|
|
866
|
+
const blocked = PinokioPathRemoval.blockedDetails(payload)
|
|
867
|
+
if (!blocked && (!response.ok || (payload && payload.error))) {
|
|
868
|
+
const message = payload && payload.error
|
|
869
|
+
throw new Error(typeof message === "string" ? message : `Cleanup failed (${response.status})`)
|
|
870
|
+
}
|
|
871
|
+
return payload
|
|
872
|
+
}
|
|
873
|
+
})
|
|
874
|
+
if (result && result.success) {
|
|
875
|
+
setTimeout(() => window.location.reload(), 0)
|
|
876
|
+
} else if (result && result.cancelled) {
|
|
877
|
+
navigateToCallback()
|
|
878
|
+
}
|
|
854
879
|
} else if (packet.type === "error") {
|
|
855
880
|
if (typeof packet.data === "string" && packet.data.includes("__PINOKIO_BLOCKER__")) {
|
|
856
881
|
return
|
package/server/views/net.ejs
CHANGED
|
@@ -2361,15 +2361,13 @@ document.addEventListener("click", async (e) => {
|
|
|
2361
2361
|
actions: "hidden"
|
|
2362
2362
|
}
|
|
2363
2363
|
});
|
|
2364
|
-
let res = await fetch("/pinokio/delete", {
|
|
2364
|
+
let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
2365
2365
|
method: "post",
|
|
2366
2366
|
headers: {
|
|
2367
2367
|
"Content-Type": "application/json"
|
|
2368
2368
|
},
|
|
2369
2369
|
body: JSON.stringify({ name })
|
|
2370
|
-
})
|
|
2371
|
-
return res.json()
|
|
2372
|
-
})
|
|
2370
|
+
}))
|
|
2373
2371
|
console.log("res", res)
|
|
2374
2372
|
Swal.close()
|
|
2375
2373
|
if (res) {
|
|
@@ -1537,18 +1537,18 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1537
1537
|
if (proceed) {
|
|
1538
1538
|
document.querySelector(".reset-bin-loading").classList.remove("hidden")
|
|
1539
1539
|
document.querySelector("#del-bin").classList.add("hidden")
|
|
1540
|
-
let res = await fetch("/pinokio/delete", {
|
|
1540
|
+
let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
1541
1541
|
method: "post",
|
|
1542
1542
|
headers: {
|
|
1543
1543
|
"Content-Type": "application/json"
|
|
1544
1544
|
},
|
|
1545
1545
|
body: JSON.stringify({ type: "bin" })
|
|
1546
|
-
})
|
|
1547
|
-
return res.json()
|
|
1548
|
-
})
|
|
1546
|
+
}))
|
|
1549
1547
|
console.log(res)
|
|
1550
1548
|
document.querySelector(".reset-bin-loading").classList.add("hidden")
|
|
1551
|
-
if (res.
|
|
1549
|
+
if (res.cancelled) {
|
|
1550
|
+
document.querySelector("#del-bin").classList.remove("hidden")
|
|
1551
|
+
} else if (res.error) {
|
|
1552
1552
|
alert(res.error)
|
|
1553
1553
|
} else {
|
|
1554
1554
|
location.href = location.href
|
|
@@ -1561,18 +1561,18 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
1561
1561
|
if (proceed) {
|
|
1562
1562
|
document.querySelector(".reset-cache-loading").classList.remove("hidden")
|
|
1563
1563
|
document.querySelector("#del-cache").classList.add("hidden")
|
|
1564
|
-
let res = await fetch("/pinokio/delete", {
|
|
1564
|
+
let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
1565
1565
|
method: "post",
|
|
1566
1566
|
headers: {
|
|
1567
1567
|
"Content-Type": "application/json"
|
|
1568
1568
|
},
|
|
1569
1569
|
body: JSON.stringify({ type: "cache" })
|
|
1570
|
-
})
|
|
1571
|
-
return res.json()
|
|
1572
|
-
})
|
|
1570
|
+
}))
|
|
1573
1571
|
console.log(res)
|
|
1574
1572
|
document.querySelector(".reset-cache-loading").classList.add("hidden")
|
|
1575
|
-
if (res.
|
|
1573
|
+
if (res.cancelled) {
|
|
1574
|
+
document.querySelector("#del-cache").classList.remove("hidden")
|
|
1575
|
+
} else if (res.error) {
|
|
1576
1576
|
alert(res.error)
|
|
1577
1577
|
} else {
|
|
1578
1578
|
location.href = location.href
|
package/server/views/setup.ejs
CHANGED
|
@@ -389,17 +389,17 @@
|
|
|
389
389
|
if (proceed) {
|
|
390
390
|
document.querySelector(".reset-bin-loading").classList.remove("hidden")
|
|
391
391
|
document.querySelector("#del-bin").classList.add("hidden")
|
|
392
|
-
let res = await fetch("/pinokio/delete", {
|
|
392
|
+
let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
393
393
|
method: "post",
|
|
394
394
|
headers: {
|
|
395
395
|
"Content-Type": "application/json"
|
|
396
396
|
},
|
|
397
397
|
body: JSON.stringify({ type: "bin" })
|
|
398
|
-
})
|
|
399
|
-
return res.json()
|
|
400
|
-
})
|
|
398
|
+
}))
|
|
401
399
|
document.querySelector(".reset-bin-loading").classList.add("hidden")
|
|
402
|
-
if (res.
|
|
400
|
+
if (res.cancelled) {
|
|
401
|
+
document.querySelector("#del-bin").classList.remove("hidden")
|
|
402
|
+
} else if (res.error) {
|
|
403
403
|
alert(res.error)
|
|
404
404
|
} else {
|
|
405
405
|
document.querySelector("#install-form").submit()
|
|
@@ -3339,18 +3339,18 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|
|
3339
3339
|
if (proceed) {
|
|
3340
3340
|
document.querySelector(".reset-bin-loading").classList.remove("hidden")
|
|
3341
3341
|
document.querySelector("#del-bin").classList.add("hidden")
|
|
3342
|
-
let res = await fetch("/pinokio/delete", {
|
|
3342
|
+
let res = await PinokioPathRemoval.request(() => fetch("/pinokio/delete", {
|
|
3343
3343
|
method: "post",
|
|
3344
3344
|
headers: {
|
|
3345
3345
|
"Content-Type": "application/json"
|
|
3346
3346
|
},
|
|
3347
3347
|
body: JSON.stringify({ type: "bin" })
|
|
3348
|
-
})
|
|
3349
|
-
return res.json()
|
|
3350
|
-
})
|
|
3348
|
+
}))
|
|
3351
3349
|
console.log(res)
|
|
3352
3350
|
document.querySelector(".reset-bin-loading").classList.add("hidden")
|
|
3353
|
-
if (res.
|
|
3351
|
+
if (res.cancelled) {
|
|
3352
|
+
document.querySelector("#del-bin").classList.remove("hidden")
|
|
3353
|
+
} else if (res.error) {
|
|
3354
3354
|
alert(res.error)
|
|
3355
3355
|
} else {
|
|
3356
3356
|
//location.href = location.href
|
package/test/conda-bin.test.js
CHANGED
|
@@ -262,7 +262,7 @@ test('Conda install replaces the stale runtime and rebuilds declared Conda modul
|
|
|
262
262
|
)
|
|
263
263
|
})
|
|
264
264
|
|
|
265
|
-
test('Conda replacement stops
|
|
265
|
+
test('Conda replacement stops a running managed Caddy without restoring it', async () => {
|
|
266
266
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-caddy-lifecycle-'))
|
|
267
267
|
await createMiniforge(root)
|
|
268
268
|
const kernel = createKernel(root, 'win32')
|
|
@@ -277,10 +277,6 @@ test('Conda replacement stops, preserves, and restarts a running managed Caddy',
|
|
|
277
277
|
events.push('caddy-stop')
|
|
278
278
|
caddyRunning = false
|
|
279
279
|
},
|
|
280
|
-
start: async () => {
|
|
281
|
-
events.push('caddy-start')
|
|
282
|
-
caddyRunning = true
|
|
283
|
-
},
|
|
284
280
|
}
|
|
285
281
|
kernel.bin.installed.conda = new Set(['caddy'])
|
|
286
282
|
kernel.bin.mod = { caddy }
|
|
@@ -311,9 +307,8 @@ test('Conda replacement stops, preserves, and restarts a running managed Caddy',
|
|
|
311
307
|
|
|
312
308
|
assert.ok(events.indexOf('caddy-stop') < events.indexOf('remove-miniforge'))
|
|
313
309
|
assert.ok(events.indexOf('remove-miniforge') < events.indexOf('bootstrap'))
|
|
314
|
-
assert.
|
|
315
|
-
assert.
|
|
316
|
-
assert.equal(caddyRunning, true)
|
|
310
|
+
assert.doesNotMatch(condaInstall.message[1], /caddy=/)
|
|
311
|
+
assert.equal(caddyRunning, false)
|
|
317
312
|
})
|
|
318
313
|
|
|
319
314
|
test('Conda install replaces legacy miniconda with a compatibility alias to miniforge', async () => {
|
|
@@ -452,7 +447,7 @@ test('Conda install propagates bootstrap failure after replacing the runtime', a
|
|
|
452
447
|
)
|
|
453
448
|
})
|
|
454
449
|
|
|
455
|
-
test('Conda install reports
|
|
450
|
+
test('Conda install reports recovery details when the old runtime cannot be removed', async () => {
|
|
456
451
|
const root = await fs.mkdtemp(path.join(os.tmpdir(), 'pinokio-conda-runtime-locked-'))
|
|
457
452
|
await createLegacyMiniconda(root)
|
|
458
453
|
const kernel = createKernel(root)
|
|
@@ -467,10 +462,15 @@ test('Conda install reports manual recovery when the old runtime cannot be remov
|
|
|
467
462
|
}
|
|
468
463
|
|
|
469
464
|
try {
|
|
465
|
+
const packets = []
|
|
470
466
|
await assert.rejects(
|
|
471
|
-
conda._install({ dependencies: [] }, () => {}),
|
|
472
|
-
/delete that folder manually/
|
|
467
|
+
conda._install({ dependencies: [] }, (data, type) => packets.push({ data, type })),
|
|
468
|
+
process.platform === 'win32' ? /__PINOKIO_BLOCKER__/ : /delete that folder manually/
|
|
473
469
|
)
|
|
470
|
+
if (process.platform === 'win32') {
|
|
471
|
+
const blocked = packets.find((packet) => packet.type === 'path.remove.blocked')
|
|
472
|
+
assert.equal(blocked && blocked.data && blocked.data.code, 'PINOKIO_PATH_REMOVE_BLOCKED')
|
|
473
|
+
}
|
|
474
474
|
} finally {
|
|
475
475
|
fsModule.promises.rm = originalRm
|
|
476
476
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
if (process.platform !== "win32") {
|
|
2
|
+
process.exit(2)
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
const koffi = require("koffi")
|
|
6
|
+
const kernel32 = koffi.load("kernel32.dll")
|
|
7
|
+
const loadLibrary = kernel32.func("void * __stdcall LoadLibraryW(str16 path)")
|
|
8
|
+
const freeLibrary = kernel32.func("int32_t __stdcall FreeLibrary(void *module)")
|
|
9
|
+
|
|
10
|
+
const moduleHandle = loadLibrary(process.argv[2])
|
|
11
|
+
if (!moduleHandle) {
|
|
12
|
+
process.stderr.write("LoadLibraryW failed\n")
|
|
13
|
+
process.exit(1)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
process.stdout.write("READY\n")
|
|
17
|
+
process.stdin.resume()
|
|
18
|
+
process.stdin.once("data", () => {
|
|
19
|
+
freeLibrary(moduleHandle)
|
|
20
|
+
process.exit(0)
|
|
21
|
+
})
|