qdd-framework 2.10.0-rc.1 → 2.10.0-rc.11
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/README.md +4 -1
- package/bin/qdd.js +59 -16
- package/install.js +171 -11
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
## 🚀 Instalación Rápida
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
npm install -g qdd-framework
|
|
13
|
+
npm install -g qdd-framework --allow-scripts=qdd-framework
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
npm 12 no corre los scripts de instalación sin esa bandera. Si instalas sin ella, la primera vez que uses `qdd` se baja su
|
|
17
|
+
binario desde el release de GitHub de esa versión, fuera del bloqueo de npm.
|
|
18
|
+
|
|
16
19
|
> **Conflicto con el paquete `qdd` de npm:** existe un paquete ajeno llamado `qdd` (no pertenece a QDD Framework) que también instala un comando `qdd`. Si lo tienes instalado globalmente, desinstálalo antes (`npm uninstall -g qdd`) para que `qdd` apunte a QDD Framework. Desde v1.9.22 su presencia ya no rompe la instalación (antes fallaba con `EISDIR`).
|
|
17
20
|
|
|
18
21
|
---
|
package/bin/qdd.js
CHANGED
|
@@ -2,26 +2,69 @@
|
|
|
2
2
|
|
|
3
3
|
const { spawnSync } = require('child_process');
|
|
4
4
|
const path = require('path');
|
|
5
|
-
const
|
|
5
|
+
const fs = require('fs');
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
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
|
+
}
|
|
9
18
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
19
|
+
function versionDelPaquete() {
|
|
20
|
+
try {
|
|
21
|
+
return require('../package.json').version;
|
|
22
|
+
} catch (_) {
|
|
23
|
+
return '';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
13
26
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
console.error('[QDD] qdd se está actualizando: inténtalo de nuevo en un momento.');
|
|
17
|
-
console.error('[QDD] Si sigue así, reinstala el paquete con: npm install -g qdd-framework');
|
|
18
|
-
process.exit(75);
|
|
27
|
+
function binarioActual() {
|
|
28
|
+
return rutaDelBinario({ platform: process.platform, env: process.env, dir: __dirname, version: versionDelPaquete(), existe: fs.existsSync });
|
|
19
29
|
}
|
|
20
30
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
31
|
+
// Con npm 12, quien instala sin --allow-scripts=qdd-framework no corrió el postinstall (FND-143): el primer qdd baja el
|
|
32
|
+
// binario con el mismo instalador. Lo que escribe va a stderr: otro programa puede estar leyendo la salida de qdd.
|
|
33
|
+
function bajarAlPrimerUso() {
|
|
34
|
+
const instalador = path.join(__dirname, '..', 'install.js');
|
|
35
|
+
if (fs.existsSync(binarioActual()) || !fs.existsSync(instalador)) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
console.error('[QDD] qdd no tiene su binario: lo bajo ahora, porque npm no corrió su instalación.');
|
|
39
|
+
spawnSync(process.execPath, [instalador, '--primer-uso'], { stdio: ['ignore', 2, 'inherit'] });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function main() {
|
|
43
|
+
bajarAlPrimerUso();
|
|
44
|
+
const binaryPath = binarioActual();
|
|
45
|
+
|
|
46
|
+
const result = spawnSync(binaryPath, process.argv.slice(2), {
|
|
47
|
+
stdio: 'inherit'
|
|
48
|
+
});
|
|
49
|
+
|
|
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
|
+
}
|
|
62
|
+
|
|
63
|
+
process.exit(result.status === null ? 1 : result.status);
|
|
25
64
|
}
|
|
26
65
|
|
|
27
|
-
|
|
66
|
+
module.exports = { rutaDelBinario };
|
|
67
|
+
|
|
68
|
+
if (require.main === module) {
|
|
69
|
+
main();
|
|
70
|
+
}
|
package/install.js
CHANGED
|
@@ -9,6 +9,8 @@ const VERSION = 'v' + pkg.version;
|
|
|
9
9
|
const REPO = 'trdago/qdd-framework';
|
|
10
10
|
// TOPE_VERSION_MS: el antivirus puede demorar la primera ejecución de un binario recién descargado.
|
|
11
11
|
const TOPE_VERSION_MS = 60000;
|
|
12
|
+
// TOPE_TURNO_MS: un turno más viejo que esto quedó abandonado; bajar el binario tarda mucho menos.
|
|
13
|
+
const TOPE_TURNO_MS = 5 * 60 * 1000;
|
|
12
14
|
|
|
13
15
|
const platformMap = {
|
|
14
16
|
win32: 'windows',
|
|
@@ -69,10 +71,17 @@ function main() {
|
|
|
69
71
|
const binaryName = `qdd${binaryExt}`;
|
|
70
72
|
const binDir = path.join(__dirname, 'bin');
|
|
71
73
|
|
|
74
|
+
const carpeta = carpetaDeVersiones({ os, env: process.env });
|
|
75
|
+
const destino = destinoDelBinario({ carpeta, version: pkg.version, binDir, binaryName });
|
|
76
|
+
|
|
72
77
|
if (!fs.existsSync(binDir)) {
|
|
73
78
|
fs.mkdirSync(binDir, { recursive: true });
|
|
74
79
|
}
|
|
75
80
|
|
|
81
|
+
if (process.argv.includes('--primer-uso')) {
|
|
82
|
+
pedirTurno(path.join(binDir, '.bajando'));
|
|
83
|
+
}
|
|
84
|
+
|
|
76
85
|
const binarioLocal = resolverBinarioLocal(__dirname, binaryName);
|
|
77
86
|
if (binarioLocal) {
|
|
78
87
|
console.log(`[QDD] Binario local detectado en ${binarioLocal}. Usando copia local para desarrollo...`);
|
|
@@ -82,13 +91,76 @@ function main() {
|
|
|
82
91
|
process.exit(0);
|
|
83
92
|
}
|
|
84
93
|
|
|
85
|
-
|
|
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
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// tomarTurno: varios qdd sin binario a la vez (un panel, por ejemplo) no bajan cada uno el suyo.
|
|
119
|
+
function tomarTurno(ruta) {
|
|
120
|
+
try {
|
|
121
|
+
fs.closeSync(fs.openSync(ruta, 'wx'));
|
|
122
|
+
return true;
|
|
123
|
+
} catch (err) {
|
|
124
|
+
if (err.code !== 'EEXIST') {
|
|
125
|
+
throw err;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (Date.now() - fs.statSync(ruta).mtimeMs < TOPE_TURNO_MS) {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
fs.rmSync(ruta, { force: true });
|
|
132
|
+
return tomarTurno(ruta);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// pedirTurno sale con 75, el «todavía no» de los pedidos, si otro qdd ya lo está bajando.
|
|
136
|
+
function pedirTurno(ruta) {
|
|
137
|
+
try {
|
|
138
|
+
if (!tomarTurno(ruta)) {
|
|
139
|
+
console.error('[QDD] Otro proceso ya está bajando el binario.');
|
|
140
|
+
process.exit(75);
|
|
141
|
+
}
|
|
142
|
+
} catch (err) {
|
|
143
|
+
fallar(`no se pudo escribir en la carpeta del paquete: ${err.message}`);
|
|
144
|
+
}
|
|
145
|
+
process.on('exit', () => fs.rmSync(ruta, { force: true }));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// carpetaDeDescarga es propia de este proceso: un postinstall y un primer uso pueden correr a la vez.
|
|
149
|
+
function carpetaDeDescarga() {
|
|
150
|
+
try {
|
|
151
|
+
const carpeta = fs.mkdtempSync(path.join(__dirname, 'descarga-'));
|
|
152
|
+
process.on('exit', () => fs.rmSync(carpeta, { recursive: true, force: true }));
|
|
153
|
+
return carpeta;
|
|
154
|
+
} catch (err) {
|
|
155
|
+
return fallar(`no se pudo escribir en la carpeta del paquete: ${err.message}`);
|
|
156
|
+
}
|
|
86
157
|
}
|
|
87
158
|
|
|
88
159
|
// 2. Descarga desde GitHub Releases
|
|
89
|
-
function descargarDesdeRelease({ os, arch, ext, binaryName, binDir }) {
|
|
160
|
+
function descargarDesdeRelease({ os, arch, ext, binaryName, binDir, destino, carpeta }) {
|
|
90
161
|
const url = `https://github.com/${REPO}/releases/download/${VERSION}/qdd_${os}_${arch}.${ext}`;
|
|
91
|
-
const
|
|
162
|
+
const descarga = carpetaDeDescarga();
|
|
163
|
+
const downloadDest = path.join(descarga, `qdd-download.${ext}`);
|
|
92
164
|
|
|
93
165
|
console.log(`[QDD] Descargando binario nativo para ${os}-${arch}...`);
|
|
94
166
|
console.log(`[QDD] URL: ${url}`);
|
|
@@ -121,9 +193,9 @@ function descargarDesdeRelease({ os, arch, ext, binaryName, binDir }) {
|
|
|
121
193
|
function extractBinary() {
|
|
122
194
|
console.log('[QDD] Extrayendo...');
|
|
123
195
|
try {
|
|
124
|
-
const bin = instalarDescarga({ os, paquete: downloadDest, carpeta:
|
|
196
|
+
const bin = instalarDescarga({ os, paquete: downloadDest, carpeta: descarga, binaryName, binDir, env: process.env, destino });
|
|
125
197
|
console.log('[QDD] ¡Instalación nativa completada exitosamente!');
|
|
126
|
-
|
|
198
|
+
terminarInstalacion({ bin, carpeta });
|
|
127
199
|
} catch (err) {
|
|
128
200
|
fallar(`no se pudo instalar el binario: ${err.message}`);
|
|
129
201
|
}
|
|
@@ -140,8 +212,96 @@ function comandoExtraer(os, paquete, destino, env) {
|
|
|
140
212
|
return { programa: 'tar', args: ['-xzf', paquete, '-C', destino] };
|
|
141
213
|
}
|
|
142
214
|
|
|
143
|
-
//
|
|
144
|
-
|
|
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) }) {
|
|
145
305
|
const { programa, args } = comandoExtraer(os, paquete, carpeta, env);
|
|
146
306
|
execFileSync(programa, args, { stdio: 'pipe' });
|
|
147
307
|
const extraido = path.join(carpeta, binaryName);
|
|
@@ -150,8 +310,8 @@ function instalarDescarga({ os, paquete, carpeta, binaryName, binDir, env }) {
|
|
|
150
310
|
}
|
|
151
311
|
fs.chmodSync(extraido, 0o755);
|
|
152
312
|
execFileSync(extraido, ['--version'], { stdio: 'pipe', timeout: TOPE_VERSION_MS });
|
|
153
|
-
|
|
154
|
-
|
|
313
|
+
fs.mkdirSync(path.dirname(destino), { recursive: true });
|
|
314
|
+
moverBinario(extraido, destino);
|
|
155
315
|
fs.rmSync(paquete, { force: true });
|
|
156
316
|
return destino;
|
|
157
317
|
}
|
|
@@ -164,7 +324,7 @@ function codigoDeFalla(env) {
|
|
|
164
324
|
|
|
165
325
|
function fallar(motivo) {
|
|
166
326
|
console.error(`[QDD] La instalación falló: ${motivo}`);
|
|
167
|
-
console.error('[QDD] Para reintentar: npm install -g qdd-framework');
|
|
327
|
+
console.error('[QDD] Para reintentar: npm install -g qdd-framework --allow-scripts=qdd-framework');
|
|
168
328
|
process.exit(codigoDeFalla(process.env));
|
|
169
329
|
}
|
|
170
330
|
|
|
@@ -178,7 +338,7 @@ function actualizarConsola(bin) {
|
|
|
178
338
|
}
|
|
179
339
|
}
|
|
180
340
|
|
|
181
|
-
module.exports = { esArchivo, estaDentroDeNodeModules, resolverBinarioLocal, comandoExtraer, instalarDescarga, codigoDeFalla };
|
|
341
|
+
module.exports = { esArchivo, estaDentroDeNodeModules, resolverBinarioLocal, comandoExtraer, instalarDescarga, codigoDeFalla, carpetaDeVersiones, destinoDelBinario, respondeBinario, moverBinario, instalarCopia, registrarVersion, tomarTurno };
|
|
182
342
|
|
|
183
343
|
if (require.main === module) {
|
|
184
344
|
main();
|