entexto-cli 1.2.0 → 1.3.0
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/lib/commands/sync.js +86 -16
- package/package.json +1 -1
package/lib/commands/sync.js
CHANGED
|
@@ -8,7 +8,7 @@ const ora = require('ora');
|
|
|
8
8
|
const FormData = require('form-data');
|
|
9
9
|
const chokidar = require('chokidar');
|
|
10
10
|
const { getToken } = require('../utils/config');
|
|
11
|
-
const { getProjects, deployFiles, getManifest, streamEvents } = require('../utils/api');
|
|
11
|
+
const { getProjects, deployFiles, getManifest, pullProject, streamEvents } = require('../utils/api');
|
|
12
12
|
const { hashFile, hashContent } = require('../utils/delta');
|
|
13
13
|
|
|
14
14
|
const IGNORE_NAMES = new Set([
|
|
@@ -103,9 +103,10 @@ module.exports = async function sync(options) {
|
|
|
103
103
|
process.exit(1);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
// ── 1. Delta inicial
|
|
107
|
-
console.log(chalk.bold('\n🔄
|
|
108
|
-
|
|
106
|
+
// ── 1. Delta inicial bidireccional ──────────────────────────────────────
|
|
107
|
+
console.log(chalk.bold('\n🔄 Sincronización inicial...\n'));
|
|
108
|
+
|
|
109
|
+
// 1a. Manifest remoto { ruta: hash }
|
|
109
110
|
let manifest = {};
|
|
110
111
|
try {
|
|
111
112
|
manifest = await getManifest(uuid);
|
|
@@ -113,19 +114,82 @@ module.exports = async function sync(options) {
|
|
|
113
114
|
console.log(chalk.gray(' (manifest no disponible, comparando todos)'));
|
|
114
115
|
}
|
|
115
116
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
117
|
+
// 1b. Hashes de los archivos locales
|
|
118
|
+
const todosArchivos = recolectarArchivos(absDir);
|
|
119
|
+
const localHashes = new Map();
|
|
120
|
+
for (const fp of todosArchivos) {
|
|
121
|
+
const ruta = path.relative(absDir, fp).replace(/\\/g, '/');
|
|
122
|
+
localHashes.set(ruta, hashFile(fp));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 1c. Clasificar qué hacer con cada archivo
|
|
126
|
+
const aDescargar = []; // ruta[] — remoto → local
|
|
127
|
+
const aSubir = []; // { filePath, ruta }[] — local → remoto
|
|
128
|
+
|
|
129
|
+
// Recorrer archivos remotos
|
|
130
|
+
for (const [ruta, remHash] of Object.entries(manifest)) {
|
|
131
|
+
const localHash = localHashes.get(ruta);
|
|
132
|
+
if (!localHash) {
|
|
133
|
+
// No existe localmente → descargar
|
|
134
|
+
aDescargar.push(ruta);
|
|
135
|
+
} else if (localHash === remHash) {
|
|
136
|
+
// Mismo contenido → sin cambios
|
|
121
137
|
console.log(' ' + chalk.gray('──') + ' ' + chalk.gray(ruta));
|
|
122
138
|
} else {
|
|
123
|
-
|
|
139
|
+
// Hash diferente → si el archivo local fue modificado hace < 10s, local gana
|
|
140
|
+
// de lo contrario remoto gana (remoto es fuente de verdad en sync inicial)
|
|
141
|
+
try {
|
|
142
|
+
const stat = fs.statSync(path.join(absDir, ruta));
|
|
143
|
+
if (Date.now() - stat.mtimeMs < 10000) {
|
|
144
|
+
aSubir.push({ filePath: path.join(absDir, ruta), ruta });
|
|
145
|
+
} else {
|
|
146
|
+
aDescargar.push(ruta);
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
aDescargar.push(ruta);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Archivos solo en local (no están en remoto) → subir
|
|
155
|
+
for (const [ruta] of localHashes) {
|
|
156
|
+
if (!(ruta in manifest)) {
|
|
157
|
+
aSubir.push({ filePath: path.join(absDir, ruta), ruta });
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// 1d. Descargar archivos remotos faltantes o actualizados
|
|
162
|
+
if (aDescargar.length > 0) {
|
|
163
|
+
const sp = ora(`Descargando ${aDescargar.length} archivo(s) del servidor...`).start();
|
|
164
|
+
try {
|
|
165
|
+
const pullData = await pullProject(uuid);
|
|
166
|
+
const archivos = pullData.archivos || [];
|
|
167
|
+
const contentMap = new Map(archivos.map(a => [a.ruta, a.content]));
|
|
168
|
+
sp.stop();
|
|
169
|
+
let downloaded = 0;
|
|
170
|
+
for (const ruta of aDescargar) {
|
|
171
|
+
const contenido = contentMap.get(ruta);
|
|
172
|
+
if (contenido === undefined) {
|
|
173
|
+
console.log(' ' + chalk.yellow('⚠') + ' No encontrado en pull: ' + chalk.gray(ruta));
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const destFile = path.join(absDir, ruta);
|
|
177
|
+
const destDir = path.dirname(destFile);
|
|
178
|
+
if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
|
|
179
|
+
fs.writeFileSync(destFile, contenido, 'utf8');
|
|
180
|
+
localUploadedAt.set(ruta, Date.now()); // evitar re-subida por chokidar
|
|
181
|
+
console.log(' ' + chalk.cyan('↓') + ' ' + chalk.white(ruta) + chalk.gray(' ← remoto'));
|
|
182
|
+
downloaded++;
|
|
183
|
+
}
|
|
184
|
+
console.log(chalk.green(` ✔ ${downloaded} archivo(s) descargados\n`));
|
|
185
|
+
} catch (err) {
|
|
186
|
+
sp.fail('Error descargando: ' + (err.response?.data?.error || err.message));
|
|
124
187
|
}
|
|
125
188
|
}
|
|
126
189
|
|
|
190
|
+
// 1e. Subir archivos locales nuevos o modificados recientemente
|
|
127
191
|
if (aSubir.length > 0) {
|
|
128
|
-
const sp = ora(`Subiendo ${aSubir.length} archivo(s)
|
|
192
|
+
const sp = ora(`Subiendo ${aSubir.length} archivo(s) al servidor...`).start();
|
|
129
193
|
try {
|
|
130
194
|
const form = new FormData();
|
|
131
195
|
for (const { filePath, ruta } of aSubir) {
|
|
@@ -133,13 +197,18 @@ module.exports = async function sync(options) {
|
|
|
133
197
|
localUploadedAt.set(ruta, Date.now());
|
|
134
198
|
}
|
|
135
199
|
await deployFiles(uuid, form, false);
|
|
136
|
-
sp.
|
|
137
|
-
aSubir.forEach(({ ruta }) =>
|
|
200
|
+
sp.stop();
|
|
201
|
+
aSubir.forEach(({ ruta }) =>
|
|
202
|
+
console.log(' ' + chalk.green('↑') + ' ' + chalk.white(ruta) + chalk.gray(' → remoto'))
|
|
203
|
+
);
|
|
204
|
+
console.log(chalk.green(` ✔ ${aSubir.length} archivo(s) subidos\n`));
|
|
138
205
|
} catch (err) {
|
|
139
|
-
sp.fail('Error
|
|
206
|
+
sp.fail('Error subiendo: ' + (err.response?.data?.error || err.message));
|
|
140
207
|
}
|
|
141
|
-
}
|
|
142
|
-
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (aDescargar.length === 0 && aSubir.length === 0) {
|
|
211
|
+
console.log(chalk.green(' ✔ Todo sincronizado, sin cambios.\n'));
|
|
143
212
|
}
|
|
144
213
|
|
|
145
214
|
// ── 2. Canal SSE (remoto → local) ───────────────────────────────────────
|
|
@@ -179,6 +248,7 @@ module.exports = async function sync(options) {
|
|
|
179
248
|
try {
|
|
180
249
|
if (!fs.existsSync(destDir)) fs.mkdirSync(destDir, { recursive: true });
|
|
181
250
|
fs.writeFileSync(destFile, contenido, 'utf8');
|
|
251
|
+
localUploadedAt.set(ruta, Date.now()); // evitar re-subida por chokidar
|
|
182
252
|
console.log(' ' + chalk.cyan('↓') + ' ' + chalk.white(ruta) + chalk.gray(' ← remoto'));
|
|
183
253
|
} catch {
|
|
184
254
|
console.log(' ' + chalk.red('✖') + ' No se pudo escribir: ' + ruta);
|