@glassnote/client 2.4.4 → 2.4.6
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/INSTALACION.md +14 -1
- package/autoupdate.js +4 -2
- package/bin/glassnote.js +70 -15
- package/npmMode.js +114 -0
- package/npmUpdate.js +33 -7
- package/package.json +1 -1
package/INSTALACION.md
CHANGED
|
@@ -86,7 +86,8 @@ se rompe en silencio es la que descarga la gente.
|
|
|
86
86
|
|
|
87
87
|
## Actualizaciones
|
|
88
88
|
|
|
89
|
-
Instalado por npm, el cliente comprueba el registry
|
|
89
|
+
Instalado por npm, el cliente comprueba el registry a los 5 segundos de arrancar y cada
|
|
90
|
+
hora a partir de ahí, y se actualiza solo:
|
|
90
91
|
|
|
91
92
|
- lee `desiredVersion` de los datos de usuario (`lastest` = seguir la última, o una
|
|
92
93
|
versión exacta y clavada); son las mismas claves que usaba el updater de S3, para no
|
|
@@ -95,6 +96,18 @@ Instalado por npm, el cliente comprueba el registry cada 3 horas y se actualiza
|
|
|
95
96
|
abrir. El npm **no** se corre con la app en marcha: en Windows el `electron.exe` en uso
|
|
96
97
|
está bloqueado y npm no podría reemplazarlo.
|
|
97
98
|
|
|
99
|
+
El ayudante corre con un **node de fuera del paquete**, no con el electron de la propia
|
|
100
|
+
app: ese electron vive dentro del árbol que npm va a reemplazar y en Windows lo mantenía
|
|
101
|
+
bloqueado, así que npm fallaba y la actualización no se aplicaba nunca. Se busca, en
|
|
102
|
+
orden: `GLASSNOTE_NODE`, el node anotado en `~/.glassnote/node-path` al instalar, el que
|
|
103
|
+
bajó el instalador a `~/.glassnote/node-v*`, y el del PATH. A npm se lo llama por su
|
|
104
|
+
`npm-cli.js`, no por el shim: en Windows el instalador mete su Node al PATH de esa sola
|
|
105
|
+
sesión de PowerShell, y la app —que la abre el autoarranque— no lo tendría.
|
|
106
|
+
|
|
107
|
+
`glassnote status` dice cuál se va a usar. Si sale `node de update: NO ENCONTRADO`, la
|
|
108
|
+
auto-actualización no puede funcionar en esa máquina: hay que reinstalar el cliente
|
|
109
|
+
(`irm https://glassnote.intermark.ec/install.ps1 | iex`) o instalar Node.
|
|
110
|
+
|
|
98
111
|
Por `npx` no se actualiza nada: la caché es efímera y npx ya baja la última versión cada
|
|
99
112
|
vez. Tampoco se registra el arranque automático — apuntaría a una carpeta que se limpia
|
|
100
113
|
sola.
|
package/autoupdate.js
CHANGED
|
@@ -30,10 +30,12 @@ class AutoUpdate {
|
|
|
30
30
|
this.checkForUpdates();
|
|
31
31
|
}, 5000);
|
|
32
32
|
|
|
33
|
-
// Verificación periódica cada hora
|
|
33
|
+
// Verificación periódica cada hora. Antes decía "cada hora" en el comentario pero
|
|
34
|
+
// la cuenta era 60 * 60 * 3000, o sea 3 horas: un cliente podía tardar toda una
|
|
35
|
+
// tarde en enterarse de una versión nueva.
|
|
34
36
|
this.updateInterval = setInterval(() => {
|
|
35
37
|
this.checkForUpdates();
|
|
36
|
-
}, 60 * 60 *
|
|
38
|
+
}, 60 * 60 * 1000);
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
/**
|
package/bin/glassnote.js
CHANGED
|
@@ -39,6 +39,22 @@ function npmEnv() {
|
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
// npm se invoca por su `npm-cli.js` con el node que lo trae, NO por el shim del PATH.
|
|
43
|
+
// En Windows el instalador puede bajarse un Node a ~/.glassnote y meterlo solo al PATH de
|
|
44
|
+
// la sesión de PowerShell que corrió la instalación: la app la arranca el autoarranque,
|
|
45
|
+
// con otro entorno, y ahí `npm` no existe. La auto-actualización moría en "npm no se
|
|
46
|
+
// reconoce como un comando" y nadie lo veía. Si no hay forma de resolver el npm-cli.js se
|
|
47
|
+
// vuelve al shim de siempre.
|
|
48
|
+
function runNpm(args, opts) {
|
|
49
|
+
const nodeBinary = mode.resolveNodeBinary(process.execPath);
|
|
50
|
+
const npmCli = mode.resolveNpmCli(nodeBinary);
|
|
51
|
+
const base = { stdio: 'inherit', shell: false, env: npmEnv() };
|
|
52
|
+
if (nodeBinary && npmCli) {
|
|
53
|
+
return spawnSync(nodeBinary, [npmCli].concat(args), Object.assign(base, opts || {}));
|
|
54
|
+
}
|
|
55
|
+
return spawnSync(NPM_CMD, args, Object.assign(base, { shell: IS_WIN }, opts || {}));
|
|
56
|
+
}
|
|
57
|
+
|
|
42
58
|
// userData tira de `uuid`, y este CLI corre también donde el árbol de dependencias no
|
|
43
59
|
// está (un tarball recién desempacado, un install a medias). Por eso se carga tarde y
|
|
44
60
|
// tolerando el fallo: si no se puede dejar constancia, el peor caso es que la app
|
|
@@ -188,10 +204,10 @@ function addToPathUnix() {
|
|
|
188
204
|
return { touched, line };
|
|
189
205
|
}
|
|
190
206
|
|
|
191
|
-
function addToPathWindows() {
|
|
207
|
+
function addToPathWindows(dir = mode.BIN_DIR) {
|
|
192
208
|
// Nada de `setx`: trunca el PATH a 1024 caracteres y se come el de la gente.
|
|
193
209
|
const ps = [
|
|
194
|
-
"$dir = '" +
|
|
210
|
+
"$dir = '" + dir.replace(/'/g, "''") + "'",
|
|
195
211
|
"$cur = [Environment]::GetEnvironmentVariable('Path','User')",
|
|
196
212
|
"if ($null -eq $cur) { $cur = '' }",
|
|
197
213
|
"if (($cur -split ';') -notcontains $dir) {",
|
|
@@ -204,7 +220,22 @@ function addToPathWindows() {
|
|
|
204
220
|
encoding: 'utf8',
|
|
205
221
|
});
|
|
206
222
|
const added = res.status === 0 && String(res.stdout).includes('added');
|
|
207
|
-
return { touched: added ? ['PATH de usuario (sin administrador)'] : [], line:
|
|
223
|
+
return { touched: added ? ['PATH de usuario (sin administrador)'] : [], line: dir };
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// El shim `glassnote.cmd` que crea npm invoca `node` del PATH. Cuando el Node lo bajó el
|
|
227
|
+
// instalador a ~/.glassnote, ese directorio solo quedaba en el PATH de la sesión de
|
|
228
|
+
// PowerShell que corrió la instalación: en una terminal nueva —o en cualquier proceso
|
|
229
|
+
// posterior— `glassnote` moría con «"node" no se reconoce como un comando». Se agrega el
|
|
230
|
+
// directorio del node al PATH de usuario, igual que BIN_DIR.
|
|
231
|
+
function addNodeToPathWindows() {
|
|
232
|
+
if (!IS_WIN) return null;
|
|
233
|
+
const nodeBinary = mode.resolveNodeBinary(process.execPath);
|
|
234
|
+
// Solo el node que trajimos nosotros: el del sistema ya está donde tiene que estar.
|
|
235
|
+
if (!nodeBinary || !mode.isInside(nodeBinary, mode.HOME_DIR)) return null;
|
|
236
|
+
const dir = path.dirname(nodeBinary);
|
|
237
|
+
const res = addToPathWindows(dir);
|
|
238
|
+
return res.touched.length ? dir : null;
|
|
208
239
|
}
|
|
209
240
|
|
|
210
241
|
function removeFromPathUnix() {
|
|
@@ -237,7 +268,10 @@ function removeFromPathWindows() {
|
|
|
237
268
|
"$dir = '" + mode.BIN_DIR.replace(/'/g, "''") + "'",
|
|
238
269
|
"$cur = [Environment]::GetEnvironmentVariable('Path','User')",
|
|
239
270
|
"if ($null -eq $cur) { Write-Output 'absent'; exit }",
|
|
240
|
-
|
|
271
|
+
// Se quita cualquier entrada bajo ~/.glassnote, no solo BIN_DIR: el install tambien
|
|
272
|
+
// agrega el directorio del node que bajo, y dejarlo seria una ruta muerta.
|
|
273
|
+
"$home2 = '" + mode.HOME_DIR.replace(/'/g, "''") + "'",
|
|
274
|
+
"$new = (($cur -split ';') | Where-Object { $_ -ne '' -and $_ -ne $dir -and -not $_.StartsWith($home2, [StringComparison]::OrdinalIgnoreCase) }) -join ';'",
|
|
241
275
|
'if ($new -ne $cur) {',
|
|
242
276
|
" [Environment]::SetEnvironmentVariable('Path', $new, 'User')",
|
|
243
277
|
" Write-Output 'removed'",
|
|
@@ -406,13 +440,15 @@ function cmdInstall(args) {
|
|
|
406
440
|
// Los scripts de instalación van ACTIVADOS a propósito: el binario de electron se
|
|
407
441
|
// baja en un postinstall. Con --ignore-scripts quedaría instalado y roto.
|
|
408
442
|
step(`npm install -g --prefix ${mode.NPM_PREFIX} (sin root, la primera vez tarda: baja electron)`);
|
|
409
|
-
const res =
|
|
410
|
-
stdio: 'inherit',
|
|
411
|
-
shell: IS_WIN,
|
|
412
|
-
env: npmEnv(),
|
|
413
|
-
});
|
|
443
|
+
const res = runNpm(['install', '-g', '--prefix', mode.NPM_PREFIX, spec]);
|
|
414
444
|
if (res.status !== 0) fail('npm no pudo instalar el paquete (ver el error de arriba).');
|
|
415
445
|
|
|
446
|
+
// Se anota con qué node se instaló: la app lo necesita para auto-actualizarse y no
|
|
447
|
+
// puede contar con que el PATH de la sesión gráfica tenga uno.
|
|
448
|
+
if (mode.rememberNodeBinary(process.execPath)) {
|
|
449
|
+
step(`node para las actualizaciones: ${process.execPath}`);
|
|
450
|
+
}
|
|
451
|
+
|
|
416
452
|
if (!fs.existsSync(mode.INSTALLED_PACKAGE_DIR)) {
|
|
417
453
|
fail(`npm terminó pero no encuentro ${mode.INSTALLED_PACKAGE_DIR}`);
|
|
418
454
|
}
|
|
@@ -439,6 +475,8 @@ function cmdInstall(args) {
|
|
|
439
475
|
if (!noPath) {
|
|
440
476
|
pathInfo = IS_WIN ? addToPathWindows() : addToPathUnix();
|
|
441
477
|
if (pathInfo.touched.length) step(`agregado al PATH en: ${pathInfo.touched.join(' ')}`);
|
|
478
|
+
const nodeDir = addNodeToPathWindows();
|
|
479
|
+
if (nodeDir) step(`agregado al PATH: ${nodeDir} (lo necesita el comando glassnote)`);
|
|
442
480
|
}
|
|
443
481
|
|
|
444
482
|
log('');
|
|
@@ -487,18 +525,26 @@ function cmdUpdate(args) {
|
|
|
487
525
|
const waitIdx = args.indexOf('--wait');
|
|
488
526
|
const waitMs = waitIdx !== -1 ? parseInt(args[waitIdx + 1], 10) || 0 : 0;
|
|
489
527
|
const relaunch = args.includes('--relaunch');
|
|
490
|
-
|
|
528
|
+
// Sin `--wait`, waitIdx es -1 y waitIdx+1 es 0: el filtro se comía el PRIMER
|
|
529
|
+
// posicional, así que `glassnote update 2.4.3` instalaba latest en vez de 2.4.3.
|
|
530
|
+
const positional = args.filter(
|
|
531
|
+
(a, i) => !a.startsWith('-') && !(waitIdx !== -1 && i === waitIdx + 1)
|
|
532
|
+
);
|
|
491
533
|
const version = positional[0] || 'latest';
|
|
492
534
|
|
|
493
535
|
if (waitMs > 0) sleepSync(waitMs);
|
|
494
536
|
|
|
537
|
+
// El cwd no puede estar dentro de lo que npm va a borrar: en Windows un directorio
|
|
538
|
+
// que es el cwd de un proceso vivo no se puede eliminar, y ese proceso es este.
|
|
539
|
+
try {
|
|
540
|
+
process.chdir(os.tmpdir());
|
|
541
|
+
} catch (error) {
|
|
542
|
+
/* si no se puede, npm igual lo intenta */
|
|
543
|
+
}
|
|
544
|
+
|
|
495
545
|
const spec = toSpec(version);
|
|
496
546
|
log(`glassnote — actualizando a ${spec}`);
|
|
497
|
-
const res =
|
|
498
|
-
stdio: 'inherit',
|
|
499
|
-
shell: IS_WIN,
|
|
500
|
-
env: npmEnv(),
|
|
501
|
-
});
|
|
547
|
+
const res = runNpm(['install', '-g', '--prefix', mode.NPM_PREFIX, spec]);
|
|
502
548
|
if (res.status !== 0) {
|
|
503
549
|
recordarFalloDeUpdate(version, `npm salió con ${res.status}`);
|
|
504
550
|
if (relaunch) {
|
|
@@ -511,6 +557,10 @@ function cmdUpdate(args) {
|
|
|
511
557
|
}
|
|
512
558
|
|
|
513
559
|
olvidarFalloDeUpdate();
|
|
560
|
+
// Igual que en install: si esta actualización la corrió un node de fuera del paquete,
|
|
561
|
+
// se anota para la siguiente. Los clientes instalados antes de que esto existiera no
|
|
562
|
+
// tienen el archivo, y el primer update es su oportunidad de conseguirlo.
|
|
563
|
+
mode.rememberNodeBinary(process.execPath);
|
|
514
564
|
// Se rehace en cada update: quien ya tenia el cliente instalado de antes no paso
|
|
515
565
|
// por el install, y el .app tiene que aparecerle igual (y con la version al dia).
|
|
516
566
|
const appMac = instalarAppMac();
|
|
@@ -617,6 +667,11 @@ function cmdStatus() {
|
|
|
617
667
|
log(` home: ${mode.HOME_DIR}`);
|
|
618
668
|
log(` datos: ${userDataDir()}`);
|
|
619
669
|
log(` autoarranque: ${autoStartOn}`);
|
|
670
|
+
// Sin un node fuera del paquete no hay auto-actualización posible: es lo primero que
|
|
671
|
+
// hay que mirar cuando un cliente se queda clavado en una versión vieja.
|
|
672
|
+
const nodeBinary = mode.resolveNodeBinary(process.execPath);
|
|
673
|
+
log(` node de update: ${nodeBinary || 'NO ENCONTRADO (la auto-actualización va a fallar)'}`);
|
|
674
|
+
log(` npm de update: ${mode.resolveNpmCli(nodeBinary) || `shim del PATH (${NPM_CMD})`}`);
|
|
620
675
|
if (process.platform === 'linux') {
|
|
621
676
|
let sandboxState = 'sin electron';
|
|
622
677
|
try {
|
package/npmMode.js
CHANGED
|
@@ -115,6 +115,116 @@ function sandboxFlags(electronBinary) {
|
|
|
115
115
|
return ['--no-sandbox'];
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
// ── Encontrar un node "de verdad" ──────────────────────────────────────────────────
|
|
119
|
+
//
|
|
120
|
+
// La auto-actualización lanza un ayudante que corre `npm install -g`, y ese ayudante NO
|
|
121
|
+
// puede ser el electron del propio paquete: npm reemplaza justamente ese árbol y en
|
|
122
|
+
// Windows un ejecutable en marcha está BLOQUEADO, así que npm moría con EPERM y la
|
|
123
|
+
// actualización no se aplicaba nunca. (En Linux/macOS borrar un binario en uso sí
|
|
124
|
+
// funciona: por eso el fallo solo se veía en Windows.) Hace falta un node de fuera.
|
|
125
|
+
//
|
|
126
|
+
// Tampoco vale confiar en el PATH para encontrar `npm`: en Windows el instalador puede
|
|
127
|
+
// bajarse un Node a ~/.glassnote y solo lo mete al PATH de ESA sesión de PowerShell. La
|
|
128
|
+
// app la arranca el autoarranque, con otro entorno, y ahí `npm` no existe. Por eso se
|
|
129
|
+
// busca el binario en disco, se recuerda cuál se usó al instalar, y a npm se lo invoca
|
|
130
|
+
// por su npm-cli.js en vez de por el shim.
|
|
131
|
+
const NODE_EXE = process.platform === 'win32' ? 'node.exe' : 'node';
|
|
132
|
+
const NODE_PATH_FILE = path.join(HOME_DIR, 'node-path');
|
|
133
|
+
|
|
134
|
+
function esArchivo(p) {
|
|
135
|
+
try {
|
|
136
|
+
return !!p && fs.statSync(p).isFile();
|
|
137
|
+
} catch (error) {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function usableNode(p) {
|
|
143
|
+
if (!p) return false;
|
|
144
|
+
if (path.basename(p).toLowerCase() !== NODE_EXE) return false;
|
|
145
|
+
if (!esArchivo(p)) return false;
|
|
146
|
+
// Lo que esté dentro del paquete es lo que npm va a reemplazar: no sirve.
|
|
147
|
+
if (isInside(p, INSTALLED_PACKAGE_DIR)) return false;
|
|
148
|
+
if (isInside(p, PACKAGE_ROOT)) return false;
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function readNodePathFile() {
|
|
153
|
+
try {
|
|
154
|
+
return fs.readFileSync(NODE_PATH_FILE, 'utf8').trim() || null;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// El CLI deja constancia del node con el que se instaló: es el único que se sabe seguro
|
|
161
|
+
// que existe en esta máquina, aunque no esté en el PATH de la sesión gráfica.
|
|
162
|
+
function rememberNodeBinary(binary) {
|
|
163
|
+
try {
|
|
164
|
+
if (!usableNode(binary)) return false;
|
|
165
|
+
fs.mkdirSync(HOME_DIR, { recursive: true });
|
|
166
|
+
fs.writeFileSync(NODE_PATH_FILE, realpath(binary), 'utf8');
|
|
167
|
+
return true;
|
|
168
|
+
} catch (error) {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// install.sh e install.ps1 desempacan el tarball oficial en ~/.glassnote/node-vX.Y.Z-...
|
|
174
|
+
function nodesBootstrapeados() {
|
|
175
|
+
const out = [];
|
|
176
|
+
try {
|
|
177
|
+
for (const entry of fs.readdirSync(HOME_DIR)) {
|
|
178
|
+
if (!entry.startsWith('node-v')) continue;
|
|
179
|
+
out.push(path.join(HOME_DIR, entry, NODE_EXE)); // zip de windows
|
|
180
|
+
out.push(path.join(HOME_DIR, entry, 'bin', NODE_EXE)); // tarball unix
|
|
181
|
+
}
|
|
182
|
+
} catch (error) {
|
|
183
|
+
/* ~/.glassnote puede no existir todavía */
|
|
184
|
+
}
|
|
185
|
+
return out;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function nodesEnPath() {
|
|
189
|
+
return String(process.env.PATH || '')
|
|
190
|
+
.split(path.delimiter)
|
|
191
|
+
.filter(Boolean)
|
|
192
|
+
.map((dir) => path.join(dir, NODE_EXE));
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// `preferido` es el ejecutable actual: cuando el CLI corre bajo node (npx, el ayudante)
|
|
196
|
+
// ese es el candidato correcto. Cuando corre bajo electron queda descartado solo, por
|
|
197
|
+
// estar dentro del paquete.
|
|
198
|
+
function resolveNodeBinary(preferido) {
|
|
199
|
+
const candidatos = [
|
|
200
|
+
process.env.GLASSNOTE_NODE,
|
|
201
|
+
preferido,
|
|
202
|
+
readNodePathFile(),
|
|
203
|
+
path.join(BIN_DIR, NODE_EXE),
|
|
204
|
+
]
|
|
205
|
+
.concat(nodesBootstrapeados())
|
|
206
|
+
.concat(nodesEnPath());
|
|
207
|
+
for (const candidato of candidatos) {
|
|
208
|
+
if (usableNode(candidato)) return realpath(candidato);
|
|
209
|
+
}
|
|
210
|
+
return null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// npm-cli.js siempre viaja al lado del node que lo trae; el shim del PATH, no.
|
|
214
|
+
function resolveNpmCli(nodeBinary) {
|
|
215
|
+
if (!nodeBinary) return null;
|
|
216
|
+
const dir = path.dirname(nodeBinary);
|
|
217
|
+
const candidatos = [
|
|
218
|
+
path.join(dir, 'node_modules', 'npm', 'bin', 'npm-cli.js'), // zip de windows
|
|
219
|
+
path.join(dir, '..', 'lib', 'node_modules', 'npm', 'bin', 'npm-cli.js'), // tarball unix / node del sistema
|
|
220
|
+
path.join(dir, '..', 'node_modules', 'npm', 'bin', 'npm-cli.js'),
|
|
221
|
+
];
|
|
222
|
+
for (const candidato of candidatos) {
|
|
223
|
+
if (esArchivo(candidato)) return path.normalize(candidato);
|
|
224
|
+
}
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
|
|
118
228
|
const isNpmMode = () => detect() === 'npm-global' || detect() === 'npx';
|
|
119
229
|
const isEphemeral = () => detect() === 'npx';
|
|
120
230
|
const isGlobalInstall = () => detect() === 'npm-global';
|
|
@@ -132,6 +242,10 @@ module.exports = {
|
|
|
132
242
|
sandboxIsSetuidRoot,
|
|
133
243
|
chromeSandboxPath,
|
|
134
244
|
userNamespacesUsable,
|
|
245
|
+
resolveNodeBinary,
|
|
246
|
+
resolveNpmCli,
|
|
247
|
+
rememberNodeBinary,
|
|
248
|
+
NODE_PATH_FILE,
|
|
135
249
|
isNpmMode,
|
|
136
250
|
isEphemeral,
|
|
137
251
|
isGlobalInstall,
|
package/npmUpdate.js
CHANGED
|
@@ -7,8 +7,14 @@
|
|
|
7
7
|
// se está ejecutando está bloqueado y npm no puede reemplazarlo. Se lanza un ayudante
|
|
8
8
|
// desprendido, la app se cierra, el ayudante actualiza y la vuelve a abrir. Igual en las
|
|
9
9
|
// tres plataformas, así no hay una rama por sistema operativo que solo se pruebe en uno.
|
|
10
|
+
//
|
|
11
|
+
// El ayudante corre con un node de FUERA del paquete (npmMode.resolveNodeBinary). Antes
|
|
12
|
+
// se lanzaba con el propio electron en modo node, que vive dentro del árbol que npm va a
|
|
13
|
+
// reemplazar: en Windows eso lo mantenía bloqueado y el update fallaba siempre.
|
|
10
14
|
const https = require('https');
|
|
15
|
+
const http = require('http');
|
|
11
16
|
const fs = require('fs');
|
|
17
|
+
const os = require('os');
|
|
12
18
|
const path = require('path');
|
|
13
19
|
const { spawn } = require('child_process');
|
|
14
20
|
|
|
@@ -18,7 +24,7 @@ const packageJson = require('./package.json');
|
|
|
18
24
|
|
|
19
25
|
const REGISTRY = process.env.GLASSNOTE_REGISTRY || 'https://registry.npmjs.org';
|
|
20
26
|
const CHECK_DELAY_MS = 5000;
|
|
21
|
-
const CHECK_INTERVAL_MS =
|
|
27
|
+
const CHECK_INTERVAL_MS = 60 * 60 * 1000; // cada hora
|
|
22
28
|
|
|
23
29
|
class NpmUpdate {
|
|
24
30
|
constructor() {
|
|
@@ -48,8 +54,12 @@ class NpmUpdate {
|
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
getJson(url) {
|
|
57
|
+
// El módulo va por protocolo: con `https` fijo, un GLASSNOTE_REGISTRY en http
|
|
58
|
+
// —el registry local de scripts/local-registry.js— moría en ERR_INVALID_PROTOCOL
|
|
59
|
+
// y la variable no servía para probar el auto-update.
|
|
60
|
+
const client = String(url).startsWith('http://') ? http : https;
|
|
51
61
|
return new Promise((resolve) => {
|
|
52
|
-
const req =
|
|
62
|
+
const req = client.get(url, { headers: { accept: 'application/json' } }, (res) => {
|
|
53
63
|
if (res.statusCode !== 200) {
|
|
54
64
|
res.resume();
|
|
55
65
|
console.error(`[update] HTTP ${res.statusCode} en ${url}`);
|
|
@@ -130,13 +140,27 @@ class NpmUpdate {
|
|
|
130
140
|
console.log(`[update] ${this.currentVersion} → ${version}: actualizando y reiniciando`);
|
|
131
141
|
|
|
132
142
|
const cli = path.join(npmMode.PACKAGE_ROOT, 'bin', 'glassnote.js');
|
|
133
|
-
|
|
134
|
-
//
|
|
143
|
+
|
|
144
|
+
// Un node de fuera del paquete es lo que hace que esto funcione en Windows: el
|
|
145
|
+
// ayudante no puede tener abierto ninguno de los archivos que npm va a borrar.
|
|
146
|
+
const nodeBinary = npmMode.resolveNodeBinary(process.execPath);
|
|
135
147
|
const env = Object.assign({}, process.env, {
|
|
136
|
-
ELECTRON_RUN_AS_NODE: '1',
|
|
137
148
|
GLASSNOTE_INSTALL_MODE: 'npm-global',
|
|
138
149
|
PATH: `${npmMode.BIN_DIR}${path.delimiter}${process.env.PATH || ''}`,
|
|
139
150
|
});
|
|
151
|
+
if (nodeBinary) {
|
|
152
|
+
delete env.ELECTRON_RUN_AS_NODE;
|
|
153
|
+
console.log(`[update] ayudante: ${nodeBinary}`);
|
|
154
|
+
} else {
|
|
155
|
+
// Último recurso: electron haciendo de node. En Linux/macOS actualiza igual
|
|
156
|
+
// (borrar un binario en uso está permitido); en Windows lo más probable es
|
|
157
|
+
// que npm no pueda y falle. Queda dicho en el log para que se vea por qué.
|
|
158
|
+
env.ELECTRON_RUN_AS_NODE = '1';
|
|
159
|
+
console.error(
|
|
160
|
+
'[update] no encuentro un node fuera del paquete; uso electron como node ' +
|
|
161
|
+
'(en Windows esto suele hacer fallar la actualización)'
|
|
162
|
+
);
|
|
163
|
+
}
|
|
140
164
|
|
|
141
165
|
// El ayudante corre desprendido y su salida no la veía nadie: cuando npm fallaba,
|
|
142
166
|
// el único síntoma era la app reiniciándose sola. Va a un archivo al lado de los
|
|
@@ -150,10 +174,12 @@ class NpmUpdate {
|
|
|
150
174
|
}
|
|
151
175
|
|
|
152
176
|
try {
|
|
177
|
+
// cwd fuera del paquete: en Windows no se puede borrar un directorio que es
|
|
178
|
+
// el cwd de un proceso vivo, y ese proceso sería justamente el actualizador.
|
|
153
179
|
const child = spawn(
|
|
154
|
-
process.execPath,
|
|
180
|
+
nodeBinary || process.execPath,
|
|
155
181
|
[cli, 'update', version, '--relaunch', '--wait', '4000'],
|
|
156
|
-
{ detached: true, stdio: ['ignore', salida, salida], env }
|
|
182
|
+
{ detached: true, stdio: ['ignore', salida, salida], env, cwd: os.tmpdir() }
|
|
157
183
|
);
|
|
158
184
|
child.unref();
|
|
159
185
|
} catch (error) {
|
package/package.json
CHANGED