qdd-framework 2.9.10 → 2.10.0-rc.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/bin/qdd.js +49 -20
- package/install.js +123 -11
- package/package.json +1 -1
package/bin/qdd.js
CHANGED
|
@@ -2,40 +2,69 @@
|
|
|
2
2
|
|
|
3
3
|
const { spawnSync } = require('child_process');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const os = require('os');
|
|
6
5
|
const fs = require('fs');
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
// rutaDelBinario: en Windows, qdd.exe vive fuera del paquete, en la carpeta de su versión (install.js, FND-142). Una
|
|
8
|
+
// instalación anterior a ese cambio, o sin LOCALAPPDATA, lo tiene dentro del paquete.
|
|
9
|
+
function rutaDelBinario({ platform, env, dir, version, existe }) {
|
|
10
|
+
const nombre = platform === 'win32' ? 'qdd.exe' : 'qdd';
|
|
11
|
+
const enElPaquete = path.join(dir, nombre);
|
|
12
|
+
if (platform !== 'win32' || !env.LOCALAPPDATA || !version) {
|
|
13
|
+
return enElPaquete;
|
|
14
|
+
}
|
|
15
|
+
const porVersion = path.join(env.LOCALAPPDATA, 'qdd', 'bin', version, nombre);
|
|
16
|
+
return existe(porVersion) ? porVersion : enElPaquete;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function versionDelPaquete() {
|
|
20
|
+
try {
|
|
21
|
+
return require('../package.json').version;
|
|
22
|
+
} catch (_) {
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function binarioActual() {
|
|
28
|
+
return rutaDelBinario({ platform: process.platform, env: process.env, dir: __dirname, version: versionDelPaquete(), existe: fs.existsSync });
|
|
29
|
+
}
|
|
11
30
|
|
|
12
31
|
// Con npm 12, quien instala sin --allow-scripts=qdd-framework no corrió el postinstall (FND-143): el primer qdd baja el
|
|
13
32
|
// binario con el mismo instalador. Lo que escribe va a stderr: otro programa puede estar leyendo la salida de qdd.
|
|
14
33
|
function bajarAlPrimerUso() {
|
|
15
|
-
|
|
34
|
+
const instalador = path.join(__dirname, '..', 'install.js');
|
|
35
|
+
if (fs.existsSync(binarioActual()) || !fs.existsSync(instalador)) {
|
|
16
36
|
return;
|
|
17
37
|
}
|
|
18
38
|
console.error('[QDD] qdd no tiene su binario: lo bajo ahora, porque npm no corrió su instalación.');
|
|
19
39
|
spawnSync(process.execPath, [instalador, '--primer-uso'], { stdio: ['ignore', 2, 'inherit'] });
|
|
20
40
|
}
|
|
21
41
|
|
|
22
|
-
|
|
42
|
+
function main() {
|
|
43
|
+
bajarAlPrimerUso();
|
|
44
|
+
const binaryPath = binarioActual();
|
|
23
45
|
|
|
24
|
-
const result = spawnSync(binaryPath, process.argv.slice(2), {
|
|
25
|
-
|
|
26
|
-
});
|
|
46
|
+
const result = spawnSync(binaryPath, process.argv.slice(2), {
|
|
47
|
+
stdio: 'inherit'
|
|
48
|
+
});
|
|
27
49
|
|
|
28
|
-
// Sin binario, lo más probable es que npm esté reinstalando qdd: 75 es «todavía no» para los pedidos del panel (FND-135).
|
|
29
|
-
if (result.error && result.error.code === 'ENOENT') {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
}
|
|
50
|
+
// Sin binario, lo más probable es que npm esté reinstalando qdd: 75 es «todavía no» para los pedidos del panel (FND-135).
|
|
51
|
+
if (result.error && result.error.code === 'ENOENT') {
|
|
52
|
+
console.error('[QDD] qdd no tiene su binario: se está actualizando, o npm bloqueó su instalación (npm 12 lo hace por defecto).');
|
|
53
|
+
console.error('[QDD] Si sigue así, reinstala el paquete con: npm install -g qdd-framework --allow-scripts=qdd-framework');
|
|
54
|
+
process.exit(75);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (result.error) {
|
|
58
|
+
console.error(`[QDD] No se pudo ejecutar el binario nativo ${binaryPath}: ${result.error.message}`);
|
|
59
|
+
console.error('[QDD] Reinstala el paquete con: npm install -g qdd-framework --allow-scripts=qdd-framework');
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
34
62
|
|
|
35
|
-
|
|
36
|
-
console.error(`[QDD] No se pudo ejecutar el binario nativo ${binaryPath}: ${result.error.message}`);
|
|
37
|
-
console.error('[QDD] Reinstala el paquete con: npm install -g qdd-framework --allow-scripts=qdd-framework');
|
|
38
|
-
process.exit(1);
|
|
63
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
39
64
|
}
|
|
40
65
|
|
|
41
|
-
|
|
66
|
+
module.exports = { rutaDelBinario };
|
|
67
|
+
|
|
68
|
+
if (require.main === module) {
|
|
69
|
+
main();
|
|
70
|
+
}
|
package/install.js
CHANGED
|
@@ -71,6 +71,9 @@ function main() {
|
|
|
71
71
|
const binaryName = `qdd${binaryExt}`;
|
|
72
72
|
const binDir = path.join(__dirname, 'bin');
|
|
73
73
|
|
|
74
|
+
const carpeta = carpetaDeVersiones({ os, env: process.env });
|
|
75
|
+
const destino = destinoDelBinario({ carpeta, version: pkg.version, binDir, binaryName });
|
|
76
|
+
|
|
74
77
|
if (!fs.existsSync(binDir)) {
|
|
75
78
|
fs.mkdirSync(binDir, { recursive: true });
|
|
76
79
|
}
|
|
@@ -88,7 +91,28 @@ function main() {
|
|
|
88
91
|
process.exit(0);
|
|
89
92
|
}
|
|
90
93
|
|
|
91
|
-
|
|
94
|
+
// Reinstalar la misma versión: su binario puede estar corriendo y no hace falta tocarlo.
|
|
95
|
+
if (carpeta && respondeBinario(destino)) {
|
|
96
|
+
console.log(`[QDD] La versión ${pkg.version} ya está en ${destino}.`);
|
|
97
|
+
terminarInstalacion({ bin: destino, carpeta });
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (process.env.QDD_INSTALL_BINARIO) {
|
|
102
|
+
instalarBinarioIndicado({ origen: process.env.QDD_INSTALL_BINARIO, destino, carpeta });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
descargarDesdeRelease({ os, arch, ext, binaryName, binDir, destino, carpeta });
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// QDD_INSTALL_BINARIO instala ese binario en vez de descargarlo: es como el CI prueba el paquete antes de publicarlo.
|
|
110
|
+
function instalarBinarioIndicado({ origen, destino, carpeta }) {
|
|
111
|
+
try {
|
|
112
|
+
terminarInstalacion({ bin: instalarCopia(origen, destino), carpeta });
|
|
113
|
+
} catch (err) {
|
|
114
|
+
fallar(`no se pudo instalar ${origen}: ${err.message}`);
|
|
115
|
+
}
|
|
92
116
|
}
|
|
93
117
|
|
|
94
118
|
// tomarTurno: varios qdd sin binario a la vez (un panel, por ejemplo) no bajan cada uno el suyo.
|
|
@@ -133,10 +157,10 @@ function carpetaDeDescarga() {
|
|
|
133
157
|
}
|
|
134
158
|
|
|
135
159
|
// 2. Descarga desde GitHub Releases
|
|
136
|
-
function descargarDesdeRelease({ os, arch, ext, binaryName, binDir }) {
|
|
160
|
+
function descargarDesdeRelease({ os, arch, ext, binaryName, binDir, destino, carpeta }) {
|
|
137
161
|
const url = `https://github.com/${REPO}/releases/download/${VERSION}/qdd_${os}_${arch}.${ext}`;
|
|
138
|
-
const
|
|
139
|
-
const downloadDest = path.join(
|
|
162
|
+
const descarga = carpetaDeDescarga();
|
|
163
|
+
const downloadDest = path.join(descarga, `qdd-download.${ext}`);
|
|
140
164
|
|
|
141
165
|
console.log(`[QDD] Descargando binario nativo para ${os}-${arch}...`);
|
|
142
166
|
console.log(`[QDD] URL: ${url}`);
|
|
@@ -169,9 +193,9 @@ function descargarDesdeRelease({ os, arch, ext, binaryName, binDir }) {
|
|
|
169
193
|
function extractBinary() {
|
|
170
194
|
console.log('[QDD] Extrayendo...');
|
|
171
195
|
try {
|
|
172
|
-
const bin = instalarDescarga({ os, paquete: downloadDest, carpeta, binaryName, binDir, env: process.env });
|
|
196
|
+
const bin = instalarDescarga({ os, paquete: downloadDest, carpeta: descarga, binaryName, binDir, env: process.env, destino });
|
|
173
197
|
console.log('[QDD] ¡Instalación nativa completada exitosamente!');
|
|
174
|
-
|
|
198
|
+
terminarInstalacion({ bin, carpeta });
|
|
175
199
|
} catch (err) {
|
|
176
200
|
fallar(`no se pudo instalar el binario: ${err.message}`);
|
|
177
201
|
}
|
|
@@ -188,8 +212,96 @@ function comandoExtraer(os, paquete, destino, env) {
|
|
|
188
212
|
return { programa: 'tar', args: ['-xzf', paquete, '-C', destino] };
|
|
189
213
|
}
|
|
190
214
|
|
|
191
|
-
//
|
|
192
|
-
|
|
215
|
+
// En Windows, npm no puede reemplazar un qdd.exe en uso, y siempre hay uno: el panel y los pedidos corren desde él (issue
|
|
216
|
+
// #107, FND-142). Por eso ahí el binario vive fuera del paquete, en %LOCALAPPDATA%\qdd\bin\<versión>\qdd.exe: lo que
|
|
217
|
+
// corre se queda con su versión y npm no se topa con nada. bin\actual.txt dice cuál es la instalada: lo que corre lo
|
|
218
|
+
// mira para saber que tiene que cerrarse. Linux y macOS pueden reemplazar un binario en uso: siguen con él en el paquete.
|
|
219
|
+
function carpetaDeVersiones({ os, env }) {
|
|
220
|
+
if (os !== 'windows' || !env.LOCALAPPDATA) {
|
|
221
|
+
return '';
|
|
222
|
+
}
|
|
223
|
+
return path.join(env.LOCALAPPDATA, 'qdd', 'bin');
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function destinoDelBinario({ carpeta, version, binDir, binaryName }) {
|
|
227
|
+
if (!carpeta) {
|
|
228
|
+
return path.join(binDir, binaryName);
|
|
229
|
+
}
|
|
230
|
+
return path.join(carpeta, version, binaryName);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function respondeBinario(ruta) {
|
|
234
|
+
try {
|
|
235
|
+
execFileSync(ruta, ['--version'], { stdio: 'pipe', timeout: TOPE_VERSION_MS });
|
|
236
|
+
return true;
|
|
237
|
+
} catch (_) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// moverBinario copia si el destino está en otro volumen: el prefijo de npm y %LOCALAPPDATA% pueden estarlo.
|
|
243
|
+
function moverBinario(origen, destino, renombrar = fs.renameSync) {
|
|
244
|
+
try {
|
|
245
|
+
renombrar(origen, destino);
|
|
246
|
+
return;
|
|
247
|
+
} catch (err) {
|
|
248
|
+
if (err.code !== 'EXDEV') {
|
|
249
|
+
throw err;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
copiarBinario(origen, destino);
|
|
253
|
+
fs.rmSync(origen, { force: true });
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// copiarBinario nunca deja un binario a medias con el nombre final.
|
|
257
|
+
function copiarBinario(origen, destino) {
|
|
258
|
+
const temporal = destino + '.nuevo';
|
|
259
|
+
fs.copyFileSync(origen, temporal);
|
|
260
|
+
fs.renameSync(temporal, destino);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function instalarCopia(origen, destino) {
|
|
264
|
+
execFileSync(origen, ['--version'], { stdio: 'pipe', timeout: TOPE_VERSION_MS });
|
|
265
|
+
fs.mkdirSync(path.dirname(destino), { recursive: true });
|
|
266
|
+
copiarBinario(origen, destino);
|
|
267
|
+
return destino;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// registrarVersion avisa a lo que corre que hay otra versión y borra las viejas: quedan esta y la anterior. Lo que no se
|
|
271
|
+
// puede borrar sigue corriendo: se borrará en otra actualización.
|
|
272
|
+
function registrarVersion({ carpeta, version, borrar = fs.rmSync }) {
|
|
273
|
+
const puntero = path.join(carpeta, 'actual.txt');
|
|
274
|
+
const anterior = esArchivo(puntero) ? fs.readFileSync(puntero, 'utf8').trim() : '';
|
|
275
|
+
if (anterior !== version) {
|
|
276
|
+
fs.writeFileSync(puntero, version);
|
|
277
|
+
}
|
|
278
|
+
for (const nombre of fs.readdirSync(carpeta)) {
|
|
279
|
+
if (!/^\d+\.\d+\.\d+/.test(nombre) || nombre === version || nombre === anterior) {
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
try {
|
|
283
|
+
borrar(path.join(carpeta, nombre), { recursive: true, force: true });
|
|
284
|
+
} catch (_) {
|
|
285
|
+
console.log(`[QDD] La versión ${nombre} sigue en uso: se borrará más adelante.`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// terminarInstalacion: primero el panel, y al final el puntero, porque lo que corre se cierra apenas cambia.
|
|
291
|
+
function terminarInstalacion({ bin, carpeta }) {
|
|
292
|
+
actualizarConsola(bin);
|
|
293
|
+
if (!carpeta) {
|
|
294
|
+
return;
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
registrarVersion({ carpeta, version: pkg.version });
|
|
298
|
+
} catch (err) {
|
|
299
|
+
console.error('[QDD] No se pudo registrar la versión instalada:', err.message);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// instalarDescarga deja el binario en su destino solo si responde; si algo falla, lanza el error y el binario anterior sigue ahí.
|
|
304
|
+
function instalarDescarga({ os, paquete, carpeta, binaryName, binDir, env, destino = path.join(binDir, binaryName) }) {
|
|
193
305
|
const { programa, args } = comandoExtraer(os, paquete, carpeta, env);
|
|
194
306
|
execFileSync(programa, args, { stdio: 'pipe' });
|
|
195
307
|
const extraido = path.join(carpeta, binaryName);
|
|
@@ -198,8 +310,8 @@ function instalarDescarga({ os, paquete, carpeta, binaryName, binDir, env }) {
|
|
|
198
310
|
}
|
|
199
311
|
fs.chmodSync(extraido, 0o755);
|
|
200
312
|
execFileSync(extraido, ['--version'], { stdio: 'pipe', timeout: TOPE_VERSION_MS });
|
|
201
|
-
|
|
202
|
-
|
|
313
|
+
fs.mkdirSync(path.dirname(destino), { recursive: true });
|
|
314
|
+
moverBinario(extraido, destino);
|
|
203
315
|
fs.rmSync(paquete, { force: true });
|
|
204
316
|
return destino;
|
|
205
317
|
}
|
|
@@ -226,7 +338,7 @@ function actualizarConsola(bin) {
|
|
|
226
338
|
}
|
|
227
339
|
}
|
|
228
340
|
|
|
229
|
-
module.exports = { esArchivo, estaDentroDeNodeModules, resolverBinarioLocal, comandoExtraer, instalarDescarga, codigoDeFalla, tomarTurno };
|
|
341
|
+
module.exports = { esArchivo, estaDentroDeNodeModules, resolverBinarioLocal, comandoExtraer, instalarDescarga, codigoDeFalla, carpetaDeVersiones, destinoDelBinario, respondeBinario, moverBinario, instalarCopia, registrarVersion, tomarTurno };
|
|
230
342
|
|
|
231
343
|
if (require.main === module) {
|
|
232
344
|
main();
|