shilo-cli 0.3.2 → 0.6.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/README.md +73 -1
- package/bin/shilo.js +32 -6
- package/package.json +1 -1
- package/src/ShiloClient.js +254 -8
- package/src/args.js +4 -2
- package/src/commands/init.js +16 -5
- package/src/commands/login.js +13 -2
- package/src/commands/pull.js +37 -9
- package/src/commands/push.js +841 -166
- package/src/prompt.js +10 -2
- package/src/pushindex.js +156 -0
- package/src/remote.js +2 -1
- package/src/secrets.js +168 -0
- package/src/sync.js +86 -10
- package/src/textguard.js +111 -30
- package/src/token.js +72 -0
- package/src/ui.js +61 -1
- package/src/walk.js +142 -34
package/src/commands/pull.js
CHANGED
|
@@ -30,6 +30,16 @@ function safeTarget(destDir, repoPath) {
|
|
|
30
30
|
return { ok: true, target };
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/** Los bytes de un archivo local, o null si no existe o no se puede leer. */
|
|
34
|
+
function readLocalBytes(absPath) {
|
|
35
|
+
try {
|
|
36
|
+
if (!fs.existsSync(absPath) || !fs.statSync(absPath).isFile()) return null;
|
|
37
|
+
return fs.readFileSync(absPath);
|
|
38
|
+
} catch (_) {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
33
43
|
/**
|
|
34
44
|
* shilo pull [carpeta] [--project <uuid>] [--base-url <url>] [--dry-run] [--yes] [--force]
|
|
35
45
|
*
|
|
@@ -72,9 +82,13 @@ async function pull(args) {
|
|
|
72
82
|
ui.warn(`no se pudo listar ${ui.c.dim(err.folderPath || '(raíz)')} — ${err.reason}`);
|
|
73
83
|
}
|
|
74
84
|
|
|
75
|
-
// 1)
|
|
85
|
+
// 1) Descartar sólo lo que no se puede escribir con seguridad.
|
|
86
|
+
//
|
|
87
|
+
// Los binarios ya NO se saltean (Etapa 2 del PLAN_MOTOR_SHILO): el GET
|
|
88
|
+
// devuelve una URL firmada en vez de contenido, y se bajan como bytes. Lo
|
|
89
|
+
// que se saltaba antes no era una limitación del formato sino del camino:
|
|
90
|
+
// el contenido viajaba como texto y un PNG volvía mutilado.
|
|
76
91
|
const candidates = [];
|
|
77
|
-
const skippedBinary = [];
|
|
78
92
|
const unsafe = [];
|
|
79
93
|
for (const f of tree.files) {
|
|
80
94
|
const safe = safeTarget(dir, f.repoPath);
|
|
@@ -82,15 +96,12 @@ async function pull(args) {
|
|
|
82
96
|
unsafe.push({ repoPath: f.repoPath, reason: safe.reason });
|
|
83
97
|
continue;
|
|
84
98
|
}
|
|
85
|
-
|
|
86
|
-
skippedBinary.push({ repoPath: f.repoPath, reason: `mime no textual (${f.mime_type})` });
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
candidates.push({ ...f, target: safe.target });
|
|
99
|
+
candidates.push({ ...f, target: safe.target, binary: !sync.isTextMime(f.mime_type) });
|
|
90
100
|
}
|
|
91
101
|
|
|
92
102
|
for (const u of unsafe) ui.warn(`saltado ${ui.c.dim(u.repoPath)} — ${u.reason}`);
|
|
93
|
-
|
|
103
|
+
|
|
104
|
+
const binaryCount = candidates.filter((f) => f.binary).length;
|
|
94
105
|
|
|
95
106
|
// 2) Clasificar contra lo que hay en disco, sin bajar nada todavía.
|
|
96
107
|
// `maybeSame` (mismo tamaño) se confirma recién al descargar el contenido.
|
|
@@ -116,7 +127,7 @@ async function pull(args) {
|
|
|
116
127
|
` ${ui.c.yellow('en conflicto:')} ${conflicting.length} ${ui.c.dim('(difieren en tamaño del local)')}\n` +
|
|
117
128
|
` ${ui.c.dim('posiblemente iguales:')} ${maybeSame.length}\n` +
|
|
118
129
|
` ${ui.c.dim('sólo locales:')} ${onlyLocal.length} ${ui.c.dim('(el pull no los toca)')}` +
|
|
119
|
-
(
|
|
130
|
+
(binaryCount ? `\n ${ui.c.dim('binarios:')} ${binaryCount}` : '') +
|
|
120
131
|
(unsafe.length ? `\n ${ui.c.red('inseguros:')} ${unsafe.length}` : '')
|
|
121
132
|
);
|
|
122
133
|
ui.info('');
|
|
@@ -186,6 +197,23 @@ async function pull(args) {
|
|
|
186
197
|
const outcomes = await sync.runPool(toDownload, CONCURRENCY, async (f) => {
|
|
187
198
|
const creds = await mgr.valid();
|
|
188
199
|
const read = await client.readFile(projectId, f.repoPath, creds);
|
|
200
|
+
|
|
201
|
+
// Binario: el servidor no manda contenido, manda una URL firmada. Los bytes
|
|
202
|
+
// se escriben tal cual, sin encoding: pasarlos por 'utf8' es exactamente lo
|
|
203
|
+
// que corrompía los binarios antes de esta etapa.
|
|
204
|
+
if (read.file && read.file.is_binary && read.file.download_url) {
|
|
205
|
+
const bytes = await client.downloadBinary(read.file.download_url);
|
|
206
|
+
|
|
207
|
+
const currentBytes = readLocalBytes(f.target);
|
|
208
|
+
if (currentBytes !== null && currentBytes.equals(bytes)) {
|
|
209
|
+
return { repoPath: f.repoPath, skipped: true };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
fs.mkdirSync(path.dirname(f.target), { recursive: true });
|
|
213
|
+
fs.writeFileSync(f.target, bytes);
|
|
214
|
+
return { repoPath: f.repoPath, skipped: false };
|
|
215
|
+
}
|
|
216
|
+
|
|
189
217
|
const content = read.file && read.file.content != null ? read.file.content : '';
|
|
190
218
|
|
|
191
219
|
const current = sync.readLocalText(f.target);
|