react-native-update-cli 2.8.0 → 2.8.1
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/bundle.js +6 -385
- package/lib/diff.js +387 -0
- package/lib/index.js +3 -0
- package/lib/utils/app-info-parser/utils.js +0 -1
- package/lib/utils/app-info-parser/zip.js +12 -14
- package/lib/utils/latest-version/index.js +5 -4
- package/lib/utils/zip-entries.js +129 -0
- package/package.json +2 -2
- package/src/bundle.ts +1 -483
- package/src/diff.ts +405 -0
- package/src/index.ts +3 -0
- package/src/utils/app-info-parser/utils.ts +0 -4
- package/src/utils/app-info-parser/zip.ts +9 -19
- package/src/utils/latest-version/index.ts +2 -1
- package/src/utils/zip-entries.ts +96 -0
package/src/diff.ts
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import * as fs from 'fs-extra';
|
|
3
|
+
import globalDirectory from 'global-directory';
|
|
4
|
+
import { ZipFile as YazlZipFile } from 'yazl';
|
|
5
|
+
import { translateOptions } from './utils';
|
|
6
|
+
import { isPPKBundleFileName, scriptName, tempDir } from './utils/constants';
|
|
7
|
+
import { t } from './utils/i18n';
|
|
8
|
+
import { enumZipEntries, readEntry } from './utils/zip-entries';
|
|
9
|
+
|
|
10
|
+
type Diff = (oldSource?: Buffer, newSource?: Buffer) => Buffer;
|
|
11
|
+
|
|
12
|
+
const { npm, yarn } = globalDirectory;
|
|
13
|
+
export { enumZipEntries, readEntry };
|
|
14
|
+
|
|
15
|
+
const loadDiffModule = (pkgName: string): Diff | undefined => {
|
|
16
|
+
const resolvePaths = [process.cwd(), npm.packages, yarn.packages];
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const resolved = require.resolve(pkgName, { paths: resolvePaths });
|
|
20
|
+
const mod = require(resolved);
|
|
21
|
+
if (mod?.diff) {
|
|
22
|
+
return mod.diff as Diff;
|
|
23
|
+
}
|
|
24
|
+
} catch {}
|
|
25
|
+
|
|
26
|
+
return undefined;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
let hdiff: Diff | undefined;
|
|
30
|
+
hdiff = (loadDiffModule('node-hdiffpatch') as any)?.diff;
|
|
31
|
+
let bsdiff: Diff | undefined;
|
|
32
|
+
let diff: Diff;
|
|
33
|
+
bsdiff = loadDiffModule('node-bsdiff');
|
|
34
|
+
|
|
35
|
+
function basename(fn: string) {
|
|
36
|
+
const m = /^(.+\/)[^\/]+\/?$/.exec(fn);
|
|
37
|
+
return m?.[1];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
async function diffFromPPK(origin: string, next: string, output: string) {
|
|
41
|
+
fs.ensureDirSync(path.dirname(output));
|
|
42
|
+
|
|
43
|
+
const originEntries = {};
|
|
44
|
+
const originMap = {};
|
|
45
|
+
|
|
46
|
+
let originSource: Buffer | undefined;
|
|
47
|
+
|
|
48
|
+
await enumZipEntries(origin, (entry, zipFile) => {
|
|
49
|
+
originEntries[entry.fileName] = entry;
|
|
50
|
+
if (!/\/$/.test(entry.fileName)) {
|
|
51
|
+
// isFile
|
|
52
|
+
originMap[entry.crc32] = entry.fileName;
|
|
53
|
+
|
|
54
|
+
if (isPPKBundleFileName(entry.fileName)) {
|
|
55
|
+
// This is source.
|
|
56
|
+
return readEntry(entry, zipFile).then((v) => (originSource = v));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
if (!originSource) {
|
|
62
|
+
throw new Error(t('bundleFileNotFound'));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const copies = {};
|
|
66
|
+
|
|
67
|
+
const zipfile = new YazlZipFile();
|
|
68
|
+
|
|
69
|
+
const writePromise = new Promise((resolve, reject) => {
|
|
70
|
+
zipfile.outputStream.on('error', (err) => {
|
|
71
|
+
throw err;
|
|
72
|
+
});
|
|
73
|
+
zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
|
|
74
|
+
resolve(void 0);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
const addedEntry = {};
|
|
79
|
+
|
|
80
|
+
function addEntry(fn: string) {
|
|
81
|
+
//console.log(fn);
|
|
82
|
+
if (!fn || addedEntry[fn]) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const base = basename(fn);
|
|
86
|
+
if (base) {
|
|
87
|
+
addEntry(base);
|
|
88
|
+
}
|
|
89
|
+
zipfile.addEmptyDirectory(fn);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const newEntries = {};
|
|
93
|
+
|
|
94
|
+
await enumZipEntries(next, (entry, nextZipfile) => {
|
|
95
|
+
newEntries[entry.fileName] = entry;
|
|
96
|
+
|
|
97
|
+
if (/\/$/.test(entry.fileName)) {
|
|
98
|
+
// Directory
|
|
99
|
+
if (!originEntries[entry.fileName]) {
|
|
100
|
+
addEntry(entry.fileName);
|
|
101
|
+
}
|
|
102
|
+
} else if (isPPKBundleFileName(entry.fileName)) {
|
|
103
|
+
//console.log('Found bundle');
|
|
104
|
+
return readEntry(entry, nextZipfile).then((newSource) => {
|
|
105
|
+
//console.log('Begin diff');
|
|
106
|
+
zipfile.addBuffer(
|
|
107
|
+
diff(originSource, newSource),
|
|
108
|
+
`${entry.fileName}.patch`,
|
|
109
|
+
);
|
|
110
|
+
//console.log('End diff');
|
|
111
|
+
});
|
|
112
|
+
} else {
|
|
113
|
+
// If same file.
|
|
114
|
+
const originEntry = originEntries[entry.fileName];
|
|
115
|
+
if (originEntry && originEntry.crc32 === entry.crc32) {
|
|
116
|
+
// ignore
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// If moved from other place
|
|
121
|
+
if (originMap[entry.crc32]) {
|
|
122
|
+
const base = basename(entry.fileName);
|
|
123
|
+
if (!originEntries[base]) {
|
|
124
|
+
addEntry(base);
|
|
125
|
+
}
|
|
126
|
+
copies[entry.fileName] = originMap[entry.crc32];
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// New file.
|
|
131
|
+
addEntry(basename(entry.fileName));
|
|
132
|
+
|
|
133
|
+
return new Promise((resolve, reject) => {
|
|
134
|
+
nextZipfile.openReadStream(entry, (err, readStream) => {
|
|
135
|
+
if (err) {
|
|
136
|
+
return reject(err);
|
|
137
|
+
}
|
|
138
|
+
zipfile.addReadStream(readStream, entry.fileName);
|
|
139
|
+
readStream.on('end', () => {
|
|
140
|
+
//console.log('add finished');
|
|
141
|
+
resolve(void 0);
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
const deletes = {};
|
|
149
|
+
|
|
150
|
+
for (const k in originEntries) {
|
|
151
|
+
if (!newEntries[k]) {
|
|
152
|
+
console.log(t('deleteFile', { file: k }));
|
|
153
|
+
deletes[k] = 1;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
//console.log({copies, deletes});
|
|
158
|
+
zipfile.addBuffer(
|
|
159
|
+
Buffer.from(JSON.stringify({ copies, deletes })),
|
|
160
|
+
'__diff.json',
|
|
161
|
+
);
|
|
162
|
+
zipfile.end();
|
|
163
|
+
await writePromise;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
async function diffFromPackage(
|
|
167
|
+
origin: string,
|
|
168
|
+
next: string,
|
|
169
|
+
output: string,
|
|
170
|
+
originBundleName: string,
|
|
171
|
+
transformPackagePath = (v: string) => v,
|
|
172
|
+
) {
|
|
173
|
+
fs.ensureDirSync(path.dirname(output));
|
|
174
|
+
|
|
175
|
+
const originEntries = {};
|
|
176
|
+
const originMap = {};
|
|
177
|
+
|
|
178
|
+
let originSource: Buffer | undefined;
|
|
179
|
+
|
|
180
|
+
await enumZipEntries(origin, (entry, zipFile) => {
|
|
181
|
+
if (!/\/$/.test(entry.fileName)) {
|
|
182
|
+
const fn = transformPackagePath(entry.fileName);
|
|
183
|
+
if (!fn) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
//console.log(fn);
|
|
188
|
+
// isFile
|
|
189
|
+
originEntries[fn] = entry.crc32;
|
|
190
|
+
originMap[entry.crc32] = fn;
|
|
191
|
+
|
|
192
|
+
if (fn === originBundleName) {
|
|
193
|
+
// This is source.
|
|
194
|
+
return readEntry(entry, zipFile).then((v) => (originSource = v));
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
if (!originSource) {
|
|
200
|
+
throw new Error(t('bundleFileNotFound'));
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const copies = {};
|
|
204
|
+
|
|
205
|
+
const zipfile = new YazlZipFile();
|
|
206
|
+
|
|
207
|
+
const writePromise = new Promise((resolve, reject) => {
|
|
208
|
+
zipfile.outputStream.on('error', (err) => {
|
|
209
|
+
throw err;
|
|
210
|
+
});
|
|
211
|
+
zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
|
|
212
|
+
resolve(void 0);
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
await enumZipEntries(next, (entry, nextZipfile) => {
|
|
217
|
+
if (/\/$/.test(entry.fileName)) {
|
|
218
|
+
// Directory
|
|
219
|
+
zipfile.addEmptyDirectory(entry.fileName);
|
|
220
|
+
} else if (isPPKBundleFileName(entry.fileName)) {
|
|
221
|
+
//console.log('Found bundle');
|
|
222
|
+
return readEntry(entry, nextZipfile).then((newSource) => {
|
|
223
|
+
//console.log('Begin diff');
|
|
224
|
+
zipfile.addBuffer(
|
|
225
|
+
diff(originSource, newSource),
|
|
226
|
+
`${entry.fileName}.patch`,
|
|
227
|
+
);
|
|
228
|
+
//console.log('End diff');
|
|
229
|
+
});
|
|
230
|
+
} else {
|
|
231
|
+
// If same file.
|
|
232
|
+
if (originEntries[entry.fileName] === entry.crc32) {
|
|
233
|
+
copies[entry.fileName] = '';
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// If moved from other place
|
|
237
|
+
if (originMap[entry.crc32]) {
|
|
238
|
+
copies[entry.fileName] = originMap[entry.crc32];
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return new Promise((resolve, reject) => {
|
|
243
|
+
nextZipfile.openReadStream(entry, (err, readStream) => {
|
|
244
|
+
if (err) {
|
|
245
|
+
return reject(err);
|
|
246
|
+
}
|
|
247
|
+
zipfile.addReadStream(readStream, entry.fileName);
|
|
248
|
+
readStream.on('end', () => {
|
|
249
|
+
//console.log('add finished');
|
|
250
|
+
resolve(void 0);
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
zipfile.addBuffer(Buffer.from(JSON.stringify({ copies })), '__diff.json');
|
|
258
|
+
zipfile.end();
|
|
259
|
+
await writePromise;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function diffArgsCheck(args: string[], options: any, diffFn: string) {
|
|
263
|
+
const [origin, next] = args;
|
|
264
|
+
|
|
265
|
+
if (!origin || !next) {
|
|
266
|
+
console.error(t('usageDiff', { command: diffFn }));
|
|
267
|
+
process.exit(1);
|
|
268
|
+
}
|
|
269
|
+
if (options?.customDiff) {
|
|
270
|
+
diff = options.customDiff;
|
|
271
|
+
} else {
|
|
272
|
+
if (diffFn.startsWith('hdiff')) {
|
|
273
|
+
if (!hdiff) {
|
|
274
|
+
console.error(t('nodeHdiffpatchRequired', { scriptName }));
|
|
275
|
+
process.exit(1);
|
|
276
|
+
}
|
|
277
|
+
diff = hdiff;
|
|
278
|
+
} else {
|
|
279
|
+
if (!bsdiff) {
|
|
280
|
+
console.error(t('nodeBsdiffRequired', { scriptName }));
|
|
281
|
+
process.exit(1);
|
|
282
|
+
}
|
|
283
|
+
diff = bsdiff;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
const { output } = translateOptions({
|
|
288
|
+
...options,
|
|
289
|
+
tempDir,
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
return {
|
|
293
|
+
origin,
|
|
294
|
+
next,
|
|
295
|
+
realOutput: output.replace(/\$\{time\}/g, `${Date.now()}`),
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export const diffCommands = {
|
|
300
|
+
async diff({ args, options }) {
|
|
301
|
+
const { origin, next, realOutput } = diffArgsCheck(args, options, 'diff');
|
|
302
|
+
|
|
303
|
+
await diffFromPPK(origin, next, realOutput);
|
|
304
|
+
console.log(t('diffPackageGenerated', { output: realOutput }));
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
async hdiff({ args, options }) {
|
|
308
|
+
const { origin, next, realOutput } = diffArgsCheck(args, options, 'hdiff');
|
|
309
|
+
|
|
310
|
+
await diffFromPPK(origin, next, realOutput);
|
|
311
|
+
console.log(t('diffPackageGenerated', { output: realOutput }));
|
|
312
|
+
},
|
|
313
|
+
|
|
314
|
+
async diffFromApk({ args, options }) {
|
|
315
|
+
const { origin, next, realOutput } = diffArgsCheck(
|
|
316
|
+
args,
|
|
317
|
+
options,
|
|
318
|
+
'diffFromApk',
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
await diffFromPackage(
|
|
322
|
+
origin,
|
|
323
|
+
next,
|
|
324
|
+
realOutput,
|
|
325
|
+
'assets/index.android.bundle',
|
|
326
|
+
);
|
|
327
|
+
console.log(t('diffPackageGenerated', { output: realOutput }));
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
async hdiffFromApk({ args, options }) {
|
|
331
|
+
const { origin, next, realOutput } = diffArgsCheck(
|
|
332
|
+
args,
|
|
333
|
+
options,
|
|
334
|
+
'hdiffFromApk',
|
|
335
|
+
);
|
|
336
|
+
|
|
337
|
+
await diffFromPackage(
|
|
338
|
+
origin,
|
|
339
|
+
next,
|
|
340
|
+
realOutput,
|
|
341
|
+
'assets/index.android.bundle',
|
|
342
|
+
);
|
|
343
|
+
console.log(t('diffPackageGenerated', { output: realOutput }));
|
|
344
|
+
},
|
|
345
|
+
|
|
346
|
+
async diffFromApp({ args, options }) {
|
|
347
|
+
const { origin, next, realOutput } = diffArgsCheck(
|
|
348
|
+
args,
|
|
349
|
+
options,
|
|
350
|
+
'diffFromApp',
|
|
351
|
+
);
|
|
352
|
+
await diffFromPackage(
|
|
353
|
+
origin,
|
|
354
|
+
next,
|
|
355
|
+
realOutput,
|
|
356
|
+
'resources/rawfile/bundle.harmony.js',
|
|
357
|
+
);
|
|
358
|
+
console.log(t('diffPackageGenerated', { output: realOutput }));
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
async hdiffFromApp({ args, options }) {
|
|
362
|
+
const { origin, next, realOutput } = diffArgsCheck(
|
|
363
|
+
args,
|
|
364
|
+
options,
|
|
365
|
+
'hdiffFromApp',
|
|
366
|
+
);
|
|
367
|
+
await diffFromPackage(
|
|
368
|
+
origin,
|
|
369
|
+
next,
|
|
370
|
+
realOutput,
|
|
371
|
+
'resources/rawfile/bundle.harmony.js',
|
|
372
|
+
);
|
|
373
|
+
console.log(t('diffPackageGenerated', { output: realOutput }));
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
async diffFromIpa({ args, options }) {
|
|
377
|
+
const { origin, next, realOutput } = diffArgsCheck(
|
|
378
|
+
args,
|
|
379
|
+
options,
|
|
380
|
+
'diffFromIpa',
|
|
381
|
+
);
|
|
382
|
+
|
|
383
|
+
await diffFromPackage(origin, next, realOutput, 'main.jsbundle', (v) => {
|
|
384
|
+
const m = /^Payload\/[^/]+\/(.+)$/.exec(v);
|
|
385
|
+
return m?.[1];
|
|
386
|
+
});
|
|
387
|
+
|
|
388
|
+
console.log(t('diffPackageGenerated', { output: realOutput }));
|
|
389
|
+
},
|
|
390
|
+
|
|
391
|
+
async hdiffFromIpa({ args, options }) {
|
|
392
|
+
const { origin, next, realOutput } = diffArgsCheck(
|
|
393
|
+
args,
|
|
394
|
+
options,
|
|
395
|
+
'hdiffFromIpa',
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
await diffFromPackage(origin, next, realOutput, 'main.jsbundle', (v) => {
|
|
399
|
+
const m = /^Payload\/[^/]+\/(.+)$/.exec(v);
|
|
400
|
+
return m?.[1];
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
console.log(t('diffPackageGenerated', { output: realOutput }));
|
|
404
|
+
},
|
|
405
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { loadSession } from './api';
|
|
4
4
|
import { appCommands } from './app';
|
|
5
5
|
import { bundleCommands } from './bundle';
|
|
6
|
+
import { diffCommands } from './diff';
|
|
6
7
|
import { installCommands } from './install';
|
|
7
8
|
import { moduleManager } from './module-manager';
|
|
8
9
|
import { builtinModules } from './modules';
|
|
@@ -31,6 +32,7 @@ function printUsage() {
|
|
|
31
32
|
const legacyCommands = {
|
|
32
33
|
...userCommands,
|
|
33
34
|
...bundleCommands,
|
|
35
|
+
...diffCommands,
|
|
34
36
|
...appCommands,
|
|
35
37
|
...packageCommands,
|
|
36
38
|
...versionCommands,
|
|
@@ -75,6 +77,7 @@ function printUsage() {
|
|
|
75
77
|
const legacyCommands = {
|
|
76
78
|
...userCommands,
|
|
77
79
|
...bundleCommands,
|
|
80
|
+
...diffCommands,
|
|
78
81
|
...appCommands,
|
|
79
82
|
...packageCommands,
|
|
80
83
|
...versionCommands,
|
|
@@ -11,10 +11,6 @@ const isPrimitive = (value: unknown): boolean =>
|
|
|
11
11
|
value === null ||
|
|
12
12
|
['boolean', 'number', 'string', 'undefined'].includes(objectType(value));
|
|
13
13
|
|
|
14
|
-
const isBrowser = (): boolean =>
|
|
15
|
-
typeof process === 'undefined' ||
|
|
16
|
-
Object.prototype.toString.call(process) !== '[object process]';
|
|
17
|
-
|
|
18
14
|
/**
|
|
19
15
|
* map file place with resourceMap
|
|
20
16
|
* @param {Object} apkInfo // json info parsed from .apk file
|
|
@@ -1,27 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
import { decodeNullUnicode } from './utils';
|
|
2
|
+
import path from 'path';
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
const Unzip = require('isomorphic-unzip');
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
import { enumZipEntries, readEntry } from '../zip-entries';
|
|
6
7
|
|
|
7
8
|
export class Zip {
|
|
8
|
-
file: string
|
|
9
|
+
file: string;
|
|
9
10
|
unzip: any;
|
|
10
11
|
|
|
11
|
-
constructor(file: string
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
throw new Error(
|
|
15
|
-
'Param error: [file] must be an instance of Blob or File in browser.',
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
this.file = file;
|
|
19
|
-
} else {
|
|
20
|
-
if (typeof file !== 'string') {
|
|
21
|
-
throw new Error('Param error: [file] must be file path in Node.');
|
|
22
|
-
}
|
|
23
|
-
this.file = require('path').resolve(file);
|
|
12
|
+
constructor(file: string) {
|
|
13
|
+
if (typeof file !== 'string') {
|
|
14
|
+
throw new Error('Param error: [file] must be file path in Node.');
|
|
24
15
|
}
|
|
16
|
+
this.file = path.resolve(file);
|
|
25
17
|
this.unzip = new Unzip(this.file);
|
|
26
18
|
}
|
|
27
19
|
|
|
@@ -66,8 +58,6 @@ export class Zip {
|
|
|
66
58
|
|
|
67
59
|
async getEntryFromHarmonyApp(regex: RegExp) {
|
|
68
60
|
try {
|
|
69
|
-
const { enumZipEntries, readEntry } =
|
|
70
|
-
bundleZipUtils ?? (bundleZipUtils = require('../../bundle'));
|
|
71
61
|
let originSource: Buffer | Blob | undefined;
|
|
72
62
|
await enumZipEntries(this.file, (entry: any, zipFile: any) => {
|
|
73
63
|
if (regex.test(entry.fileName)) {
|
|
@@ -8,7 +8,8 @@ import type { RequestOptions as HttpsRequestOptions } from 'https';
|
|
|
8
8
|
import { homedir } from 'os';
|
|
9
9
|
import { dirname, join, parse, resolve as pathResolve } from 'path';
|
|
10
10
|
import { URL } from 'url';
|
|
11
|
-
import
|
|
11
|
+
import globalDirectory from 'global-directory';
|
|
12
|
+
const { npm, yarn } = globalDirectory;
|
|
12
13
|
|
|
13
14
|
import registryAuthToken from 'registry-auth-token';
|
|
14
15
|
import getRegistryUrl from 'registry-auth-token/registry-url';
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import os from 'os';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import * as fs from 'fs-extra';
|
|
4
|
+
import {
|
|
5
|
+
type Entry,
|
|
6
|
+
type ZipFile as YauzlZipFile,
|
|
7
|
+
open as openZipFile,
|
|
8
|
+
} from 'yauzl';
|
|
9
|
+
import { t } from './i18n';
|
|
10
|
+
|
|
11
|
+
export function readEntry(
|
|
12
|
+
entry: Entry,
|
|
13
|
+
zipFile: YauzlZipFile,
|
|
14
|
+
): Promise<Buffer> {
|
|
15
|
+
const buffers: Buffer[] = [];
|
|
16
|
+
return new Promise((resolve, reject) => {
|
|
17
|
+
zipFile.openReadStream(entry, (err, stream) => {
|
|
18
|
+
stream.on('data', (chunk: Buffer) => {
|
|
19
|
+
buffers.push(chunk);
|
|
20
|
+
});
|
|
21
|
+
stream.on('end', () => {
|
|
22
|
+
resolve(Buffer.concat(buffers));
|
|
23
|
+
});
|
|
24
|
+
stream.on('error', (err) => {
|
|
25
|
+
reject(err);
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export async function enumZipEntries(
|
|
32
|
+
zipFn: string,
|
|
33
|
+
callback: (
|
|
34
|
+
entry: Entry,
|
|
35
|
+
zipFile: YauzlZipFile,
|
|
36
|
+
nestedPath?: string,
|
|
37
|
+
) => Promise<any>,
|
|
38
|
+
nestedPath = '',
|
|
39
|
+
) {
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
openZipFile(
|
|
42
|
+
zipFn,
|
|
43
|
+
{ lazyEntries: true },
|
|
44
|
+
async (err: any, zipfile: YauzlZipFile) => {
|
|
45
|
+
if (err) {
|
|
46
|
+
return reject(err);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
zipfile.on('end', resolve);
|
|
50
|
+
zipfile.on('error', reject);
|
|
51
|
+
zipfile.on('entry', async (entry) => {
|
|
52
|
+
const fullPath = nestedPath + entry.fileName;
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
if (
|
|
56
|
+
!entry.fileName.endsWith('/') &&
|
|
57
|
+
entry.fileName.toLowerCase().endsWith('.hap')
|
|
58
|
+
) {
|
|
59
|
+
const tempDir = path.join(
|
|
60
|
+
os.tmpdir(),
|
|
61
|
+
`nested_zip_${Date.now()}`,
|
|
62
|
+
);
|
|
63
|
+
await fs.ensureDir(tempDir);
|
|
64
|
+
const tempZipPath = path.join(tempDir, 'temp.zip');
|
|
65
|
+
|
|
66
|
+
await new Promise((res, rej) => {
|
|
67
|
+
zipfile.openReadStream(entry, async (err, readStream) => {
|
|
68
|
+
if (err) return rej(err);
|
|
69
|
+
const writeStream = fs.createWriteStream(tempZipPath);
|
|
70
|
+
readStream.pipe(writeStream);
|
|
71
|
+
writeStream.on('finish', () => res(void 0));
|
|
72
|
+
writeStream.on('error', rej);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await enumZipEntries(tempZipPath, callback, `${fullPath}/`);
|
|
77
|
+
|
|
78
|
+
await fs.remove(tempDir);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const result = callback(entry, zipfile, fullPath);
|
|
82
|
+
if (result && typeof result.then === 'function') {
|
|
83
|
+
await result;
|
|
84
|
+
}
|
|
85
|
+
} catch (error) {
|
|
86
|
+
console.error(t('processingError', { error }));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
zipfile.readEntry();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
zipfile.readEntry();
|
|
93
|
+
},
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
}
|