react-native-update-cli 1.38.1 → 1.39.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/app.js +1 -1
- package/lib/bundle.js +152 -57
- package/lib/package.js +8 -8
- package/lib/utils/check-plugin.js +30 -0
- package/lib/utils/index.js +7 -5
- package/lib/utils/plugin-config.js +39 -0
- package/lib/versions.js +3 -1
- package/package.json +1 -1
- package/src/{app.js → app.ts} +6 -5
- package/src/bundle.js +184 -64
- package/src/{package.js → package.ts} +10 -11
- package/src/types.ts +2 -0
- package/src/{user.js → user.ts} +2 -2
- package/src/utils/check-plugin.ts +30 -0
- package/src/utils/{index.js → index.ts} +10 -6
- package/src/utils/plugin-config.ts +34 -0
- package/src/versions.js +3 -1
package/lib/versions.js
CHANGED
|
@@ -86,8 +86,9 @@ const commands = {
|
|
|
86
86
|
const platform = (0, _app.checkPlatform)(options.platform || await (0, _utils.question)('平台(ios/android/harmony):'));
|
|
87
87
|
const { appId } = await (0, _app.getSelectedApp)(platform);
|
|
88
88
|
const { hash } = await (0, _api.uploadFile)(fn);
|
|
89
|
+
const versionName = name || await (0, _utils.question)('输入版本名称: ') || '(未命名)';
|
|
89
90
|
const { id } = await (0, _api.post)(`/app/${appId}/version/create`, {
|
|
90
|
-
name:
|
|
91
|
+
name: versionName,
|
|
91
92
|
hash,
|
|
92
93
|
description: description || await (0, _utils.question)('输入版本描述:'),
|
|
93
94
|
metaInfo: metaInfo || await (0, _utils.question)('输入自定义的 meta info:')
|
|
@@ -105,6 +106,7 @@ const commands = {
|
|
|
105
106
|
}
|
|
106
107
|
});
|
|
107
108
|
}
|
|
109
|
+
return versionName;
|
|
108
110
|
},
|
|
109
111
|
versions: async ({ options })=>{
|
|
110
112
|
const platform = (0, _app.checkPlatform)(options.platform || await (0, _utils.question)('平台(ios/android/harmony):'));
|
package/package.json
CHANGED
package/src/{app.js → app.ts}
RENAMED
|
@@ -3,6 +3,7 @@ import fs from 'node:fs';
|
|
|
3
3
|
import Table from 'tty-table';
|
|
4
4
|
|
|
5
5
|
import { post, get, doDelete } from './api';
|
|
6
|
+
import type { Platform } from './types';
|
|
6
7
|
|
|
7
8
|
const validPlatforms = {
|
|
8
9
|
ios: 1,
|
|
@@ -10,14 +11,14 @@ const validPlatforms = {
|
|
|
10
11
|
harmony: 1,
|
|
11
12
|
};
|
|
12
13
|
|
|
13
|
-
export function checkPlatform(platform) {
|
|
14
|
+
export function checkPlatform(platform: Platform) {
|
|
14
15
|
if (!validPlatforms[platform]) {
|
|
15
16
|
throw new Error(`无法识别的平台 '${platform}'`);
|
|
16
17
|
}
|
|
17
18
|
return platform;
|
|
18
19
|
}
|
|
19
20
|
|
|
20
|
-
export function getSelectedApp(platform) {
|
|
21
|
+
export function getSelectedApp(platform: Platform) {
|
|
21
22
|
checkPlatform(platform);
|
|
22
23
|
|
|
23
24
|
if (!fs.existsSync('update.json')) {
|
|
@@ -34,7 +35,7 @@ export function getSelectedApp(platform) {
|
|
|
34
35
|
return updateInfo[platform];
|
|
35
36
|
}
|
|
36
37
|
|
|
37
|
-
export async function listApp(platform) {
|
|
38
|
+
export async function listApp(platform: Platform) {
|
|
38
39
|
const { data } = await get('/app/list');
|
|
39
40
|
const list = platform ? data.filter((v) => v.platform === platform) : data;
|
|
40
41
|
|
|
@@ -58,12 +59,12 @@ export async function listApp(platform) {
|
|
|
58
59
|
return list;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
|
-
export async function chooseApp(platform) {
|
|
62
|
+
export async function chooseApp(platform: Platform) {
|
|
62
63
|
const list = await listApp(platform);
|
|
63
64
|
|
|
64
65
|
while (true) {
|
|
65
66
|
const id = await question('输入应用 id:');
|
|
66
|
-
const app = list.find((v) => v.id === (id
|
|
67
|
+
const app = list.find((v) => v.id === Number(id));
|
|
67
68
|
if (app) {
|
|
68
69
|
return app;
|
|
69
70
|
}
|
package/src/bundle.js
CHANGED
|
@@ -3,15 +3,17 @@ import { getRNVersion, translateOptions } from './utils';
|
|
|
3
3
|
import * as fs from 'fs-extra';
|
|
4
4
|
import { ZipFile } from 'yazl';
|
|
5
5
|
import { open as openZipFile } from 'yauzl';
|
|
6
|
-
import { question,
|
|
6
|
+
import { question, checkPlugins } from './utils';
|
|
7
7
|
import { checkPlatform } from './app';
|
|
8
8
|
import { spawn, spawnSync } from 'node:child_process';
|
|
9
|
+
import semverSatisfies from 'semver/functions/satisfies';
|
|
9
10
|
const g2js = require('gradle-to-js/lib/parser');
|
|
10
|
-
import os from 'os';
|
|
11
|
+
import os from 'node:os';
|
|
11
12
|
const properties = require('properties');
|
|
12
|
-
const path = require('path');
|
|
13
13
|
|
|
14
|
-
let bsdiff
|
|
14
|
+
let bsdiff;
|
|
15
|
+
let hdiff;
|
|
16
|
+
let diff;
|
|
15
17
|
try {
|
|
16
18
|
bsdiff = require('node-bsdiff').diff;
|
|
17
19
|
} catch (e) {}
|
|
@@ -39,9 +41,9 @@ async function runReactNativeBundleCommand(
|
|
|
39
41
|
}
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
const reactNativeBundleArgs = [];
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
const envArgs = process.env.PUSHY_ENV_ARGS;
|
|
45
47
|
|
|
46
48
|
if (envArgs) {
|
|
47
49
|
Array.prototype.push.apply(
|
|
@@ -59,8 +61,19 @@ async function runReactNativeBundleCommand(
|
|
|
59
61
|
cliPath = require.resolve('@expo/cli', {
|
|
60
62
|
paths: [process.cwd()],
|
|
61
63
|
});
|
|
62
|
-
|
|
63
|
-
|
|
64
|
+
const expoCliVersion = JSON.parse(
|
|
65
|
+
fs.readFileSync(
|
|
66
|
+
require.resolve('@expo/cli/package.json', {
|
|
67
|
+
paths: [process.cwd()],
|
|
68
|
+
}),
|
|
69
|
+
),
|
|
70
|
+
).version;
|
|
71
|
+
// expo cli 0.10.17 (expo 49) 开始支持 bundle:embed
|
|
72
|
+
if (semverSatisfies(expoCliVersion, '>= 0.10.17')) {
|
|
73
|
+
usingExpo = true;
|
|
74
|
+
}
|
|
75
|
+
} catch (e) {}
|
|
76
|
+
if (!usingExpo) {
|
|
64
77
|
try {
|
|
65
78
|
// rn >= 0.75
|
|
66
79
|
cliPath = require.resolve('@react-native-community/cli/build/bin.js', {
|
|
@@ -73,8 +86,15 @@ async function runReactNativeBundleCommand(
|
|
|
73
86
|
});
|
|
74
87
|
}
|
|
75
88
|
}
|
|
76
|
-
const
|
|
77
|
-
|
|
89
|
+
const bundleParams = await checkPlugins();
|
|
90
|
+
const minifyOption = bundleParams.minify;
|
|
91
|
+
const isSentry = bundleParams.sentry;
|
|
92
|
+
const bundleCommand = usingExpo
|
|
93
|
+
? 'export:embed'
|
|
94
|
+
: platform === 'harmony'
|
|
95
|
+
? 'bundle-harmony'
|
|
96
|
+
: 'bundle';
|
|
97
|
+
if (platform === 'harmony') {
|
|
78
98
|
Array.prototype.push.apply(reactNativeBundleArgs, [
|
|
79
99
|
cliPath,
|
|
80
100
|
bundleCommand,
|
|
@@ -91,8 +111,7 @@ async function runReactNativeBundleCommand(
|
|
|
91
111
|
if (config) {
|
|
92
112
|
reactNativeBundleArgs.push('--config', config);
|
|
93
113
|
}
|
|
94
|
-
}
|
|
95
|
-
else{
|
|
114
|
+
} else {
|
|
96
115
|
Array.prototype.push.apply(reactNativeBundleArgs, [
|
|
97
116
|
cliPath,
|
|
98
117
|
bundleCommand,
|
|
@@ -107,17 +126,19 @@ async function runReactNativeBundleCommand(
|
|
|
107
126
|
'--platform',
|
|
108
127
|
platform,
|
|
109
128
|
'--reset-cache',
|
|
129
|
+
'--minify',
|
|
130
|
+
minifyOption,
|
|
110
131
|
]);
|
|
111
|
-
|
|
132
|
+
|
|
112
133
|
if (sourcemapOutput) {
|
|
113
134
|
reactNativeBundleArgs.push('--sourcemap-output', sourcemapOutput);
|
|
114
135
|
}
|
|
115
|
-
|
|
136
|
+
|
|
116
137
|
if (config) {
|
|
117
138
|
reactNativeBundleArgs.push('--config', config);
|
|
118
139
|
}
|
|
119
140
|
}
|
|
120
|
-
|
|
141
|
+
|
|
121
142
|
const reactNativeBundleProcess = spawn('node', reactNativeBundleArgs);
|
|
122
143
|
console.log(
|
|
123
144
|
`Running bundle command: node ${reactNativeBundleArgs.join(' ')}`,
|
|
@@ -147,7 +168,7 @@ async function runReactNativeBundleCommand(
|
|
|
147
168
|
properties.parse(
|
|
148
169
|
'./android/gradle.properties',
|
|
149
170
|
{ path: true },
|
|
150
|
-
|
|
171
|
+
(error, props) => {
|
|
151
172
|
if (error) {
|
|
152
173
|
console.error(error);
|
|
153
174
|
resolve(null);
|
|
@@ -166,7 +187,7 @@ async function runReactNativeBundleCommand(
|
|
|
166
187
|
fs.existsSync('ios/Pods/hermes-engine')
|
|
167
188
|
) {
|
|
168
189
|
hermesEnabled = true;
|
|
169
|
-
}else if (platform === 'harmony') {
|
|
190
|
+
} else if (platform === 'harmony') {
|
|
170
191
|
await copyHarmonyBundle(outputFolder);
|
|
171
192
|
}
|
|
172
193
|
if (hermesEnabled) {
|
|
@@ -174,6 +195,7 @@ async function runReactNativeBundleCommand(
|
|
|
174
195
|
bundleName,
|
|
175
196
|
outputFolder,
|
|
176
197
|
sourcemapOutput,
|
|
198
|
+
!isSentry,
|
|
177
199
|
);
|
|
178
200
|
}
|
|
179
201
|
resolve(null);
|
|
@@ -193,7 +215,7 @@ async function copyHarmonyBundle(outputFolder) {
|
|
|
193
215
|
}
|
|
194
216
|
await fs.remove(path.join(harmonyRawPath, 'update.json'));
|
|
195
217
|
await fs.copy('update.json', path.join(harmonyRawPath, 'update.json'));
|
|
196
|
-
|
|
218
|
+
|
|
197
219
|
await fs.ensureDir(outputFolder);
|
|
198
220
|
await fs.copy(harmonyRawPath, outputFolder);
|
|
199
221
|
} catch (error) {
|
|
@@ -237,8 +259,9 @@ async function compileHermesByteCode(
|
|
|
237
259
|
bundleName,
|
|
238
260
|
outputFolder,
|
|
239
261
|
sourcemapOutput,
|
|
262
|
+
shouldCleanSourcemap,
|
|
240
263
|
) {
|
|
241
|
-
console.log(
|
|
264
|
+
console.log('Hermes enabled, now compiling to hermes bytecode:\n');
|
|
242
265
|
// >= rn 0.69
|
|
243
266
|
const rnDir = path.dirname(
|
|
244
267
|
require.resolve('react-native', {
|
|
@@ -264,13 +287,11 @@ async function compileHermesByteCode(
|
|
|
264
287
|
if (sourcemapOutput) {
|
|
265
288
|
fs.copyFileSync(
|
|
266
289
|
sourcemapOutput,
|
|
267
|
-
path.join(outputFolder, bundleName
|
|
290
|
+
path.join(outputFolder, `${bundleName}.txt.map`),
|
|
268
291
|
);
|
|
269
292
|
args.push('-output-source-map');
|
|
270
293
|
}
|
|
271
|
-
console.log(
|
|
272
|
-
'Running hermesc: ' + hermesCommand + ' ' + args.join(' ') + '\n',
|
|
273
|
-
);
|
|
294
|
+
console.log(`Running hermesc: ${hermesCommand} ${args.join(' ')}`);
|
|
274
295
|
spawnSync(hermesCommand, args, {
|
|
275
296
|
stdio: 'ignore',
|
|
276
297
|
});
|
|
@@ -280,13 +301,13 @@ async function compileHermesByteCode(
|
|
|
280
301
|
if (!fs.existsSync(composerPath)) {
|
|
281
302
|
return;
|
|
282
303
|
}
|
|
283
|
-
console.log(
|
|
304
|
+
console.log('Composing source map');
|
|
284
305
|
spawnSync(
|
|
285
306
|
'node',
|
|
286
307
|
[
|
|
287
308
|
composerPath,
|
|
288
|
-
path.join(outputFolder, bundleName
|
|
289
|
-
path.join(outputFolder, bundleName
|
|
309
|
+
path.join(outputFolder, `${bundleName}.txt.map`),
|
|
310
|
+
path.join(outputFolder, `${bundleName}.map`),
|
|
290
311
|
'-o',
|
|
291
312
|
sourcemapOutput,
|
|
292
313
|
],
|
|
@@ -295,7 +316,96 @@ async function compileHermesByteCode(
|
|
|
295
316
|
},
|
|
296
317
|
);
|
|
297
318
|
}
|
|
298
|
-
|
|
319
|
+
if (shouldCleanSourcemap) {
|
|
320
|
+
fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async function copyDebugidForSentry(bundleName, outputFolder, sourcemapOutput) {
|
|
325
|
+
if (sourcemapOutput) {
|
|
326
|
+
let copyDebugidPath;
|
|
327
|
+
try {
|
|
328
|
+
copyDebugidPath = require.resolve(
|
|
329
|
+
'@sentry/react-native/scripts/copy-debugid.js',
|
|
330
|
+
{
|
|
331
|
+
paths: [process.cwd()],
|
|
332
|
+
},
|
|
333
|
+
);
|
|
334
|
+
} catch (error) {
|
|
335
|
+
console.error(
|
|
336
|
+
'无法找到 Sentry copy-debugid.js 脚本文件,请确保已正确安装 @sentry/react-native',
|
|
337
|
+
);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (!fs.existsSync(copyDebugidPath)) {
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
console.log('Copying debugid');
|
|
345
|
+
spawnSync(
|
|
346
|
+
'node',
|
|
347
|
+
[
|
|
348
|
+
copyDebugidPath,
|
|
349
|
+
path.join(outputFolder, `${bundleName}.txt.map`),
|
|
350
|
+
path.join(outputFolder, `${bundleName}.map`),
|
|
351
|
+
],
|
|
352
|
+
{
|
|
353
|
+
stdio: 'ignore',
|
|
354
|
+
},
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
fs.removeSync(path.join(outputFolder, `${bundleName}.txt.map`));
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
async function uploadSourcemapForSentry(
|
|
361
|
+
bundleName,
|
|
362
|
+
outputFolder,
|
|
363
|
+
sourcemapOutput,
|
|
364
|
+
version,
|
|
365
|
+
) {
|
|
366
|
+
if (sourcemapOutput) {
|
|
367
|
+
let sentryCliPath;
|
|
368
|
+
try {
|
|
369
|
+
sentryCliPath = require.resolve('@sentry/cli/bin/sentry-cli', {
|
|
370
|
+
paths: [process.cwd()],
|
|
371
|
+
});
|
|
372
|
+
} catch (error) {
|
|
373
|
+
console.error('无法找到 Sentry CLI 工具,请确保已正确安装 @sentry/cli');
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (!fs.existsSync(sentryCliPath)) {
|
|
378
|
+
return;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
spawnSync(
|
|
382
|
+
'node',
|
|
383
|
+
[sentryCliPath, 'releases', 'set-commits', version, '--auto'],
|
|
384
|
+
{
|
|
385
|
+
stdio: 'inherit',
|
|
386
|
+
},
|
|
387
|
+
);
|
|
388
|
+
console.log(`Sentry release created for version: ${version}`);
|
|
389
|
+
|
|
390
|
+
console.log('Uploading sourcemap');
|
|
391
|
+
spawnSync(
|
|
392
|
+
'node',
|
|
393
|
+
[
|
|
394
|
+
sentryCliPath,
|
|
395
|
+
'releases',
|
|
396
|
+
'files',
|
|
397
|
+
version,
|
|
398
|
+
'upload-sourcemaps',
|
|
399
|
+
'--strip-prefix',
|
|
400
|
+
path.join(process.cwd(), outputFolder),
|
|
401
|
+
path.join(outputFolder, bundleName),
|
|
402
|
+
path.join(outputFolder, `${bundleName}.map`),
|
|
403
|
+
],
|
|
404
|
+
{
|
|
405
|
+
stdio: 'inherit',
|
|
406
|
+
},
|
|
407
|
+
);
|
|
408
|
+
}
|
|
299
409
|
}
|
|
300
410
|
|
|
301
411
|
async function pack(dir, output) {
|
|
@@ -320,7 +430,7 @@ async function pack(dir, output) {
|
|
|
320
430
|
zipfile.addFile(fullPath, rel + name);
|
|
321
431
|
} else if (stat.isDirectory()) {
|
|
322
432
|
//console.log('adding: ' + rel+name+'/');
|
|
323
|
-
addDirectory(fullPath, rel
|
|
433
|
+
addDirectory(fullPath, `${rel}${name}/`);
|
|
324
434
|
}
|
|
325
435
|
}
|
|
326
436
|
}
|
|
@@ -328,14 +438,12 @@ async function pack(dir, output) {
|
|
|
328
438
|
addDirectory(dir, '');
|
|
329
439
|
|
|
330
440
|
zipfile.outputStream.on('error', (err) => reject(err));
|
|
331
|
-
zipfile.outputStream
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
resolve();
|
|
335
|
-
});
|
|
441
|
+
zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
|
|
442
|
+
resolve();
|
|
443
|
+
});
|
|
336
444
|
zipfile.end();
|
|
337
445
|
});
|
|
338
|
-
console.log(
|
|
446
|
+
console.log(`ppk热更包已生成并保存到: ${output}`);
|
|
339
447
|
}
|
|
340
448
|
|
|
341
449
|
export function readEntire(entry, zipFile) {
|
|
@@ -360,7 +468,7 @@ export function readEntire(entry, zipFile) {
|
|
|
360
468
|
|
|
361
469
|
function basename(fn) {
|
|
362
470
|
const m = /^(.+\/)[^\/]+\/?$/.exec(fn);
|
|
363
|
-
return m
|
|
471
|
+
return m?.[1];
|
|
364
472
|
}
|
|
365
473
|
|
|
366
474
|
async function diffFromPPK(origin, next, output) {
|
|
@@ -377,7 +485,10 @@ async function diffFromPPK(origin, next, output) {
|
|
|
377
485
|
// isFile
|
|
378
486
|
originMap[entry.crc32] = entry.fileName;
|
|
379
487
|
|
|
380
|
-
if (
|
|
488
|
+
if (
|
|
489
|
+
entry.fileName === 'index.bundlejs' ||
|
|
490
|
+
entry.fileName === 'bundle.harmony.js'
|
|
491
|
+
) {
|
|
381
492
|
// This is source.
|
|
382
493
|
return readEntire(entry, zipFile).then((v) => (originSource = v));
|
|
383
494
|
}
|
|
@@ -386,7 +497,7 @@ async function diffFromPPK(origin, next, output) {
|
|
|
386
497
|
|
|
387
498
|
if (!originSource) {
|
|
388
499
|
throw new Error(
|
|
389
|
-
|
|
500
|
+
'Bundle file not found! Please use default bundle file name and path.',
|
|
390
501
|
);
|
|
391
502
|
}
|
|
392
503
|
|
|
@@ -398,11 +509,9 @@ async function diffFromPPK(origin, next, output) {
|
|
|
398
509
|
zipfile.outputStream.on('error', (err) => {
|
|
399
510
|
throw err;
|
|
400
511
|
});
|
|
401
|
-
zipfile.outputStream
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
resolve();
|
|
405
|
-
});
|
|
512
|
+
zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
|
|
513
|
+
resolve();
|
|
514
|
+
});
|
|
406
515
|
});
|
|
407
516
|
|
|
408
517
|
const addedEntry = {};
|
|
@@ -439,7 +548,7 @@ async function diffFromPPK(origin, next, output) {
|
|
|
439
548
|
);
|
|
440
549
|
//console.log('End diff');
|
|
441
550
|
});
|
|
442
|
-
}else if (entry.fileName === 'bundle.harmony.js') {
|
|
551
|
+
} else if (entry.fileName === 'bundle.harmony.js') {
|
|
443
552
|
//console.log('Found bundle');
|
|
444
553
|
return readEntire(entry, nextZipfile).then((newSource) => {
|
|
445
554
|
//console.log('Begin diff');
|
|
@@ -471,7 +580,7 @@ async function diffFromPPK(origin, next, output) {
|
|
|
471
580
|
addEntry(basename(entry.fileName));
|
|
472
581
|
|
|
473
582
|
return new Promise((resolve, reject) => {
|
|
474
|
-
nextZipfile.openReadStream(entry,
|
|
583
|
+
nextZipfile.openReadStream(entry, (err, readStream) => {
|
|
475
584
|
if (err) {
|
|
476
585
|
return reject(err);
|
|
477
586
|
}
|
|
@@ -487,9 +596,9 @@ async function diffFromPPK(origin, next, output) {
|
|
|
487
596
|
|
|
488
597
|
const deletes = {};
|
|
489
598
|
|
|
490
|
-
for (
|
|
599
|
+
for (const k in originEntries) {
|
|
491
600
|
if (!newEntries[k]) {
|
|
492
|
-
console.log(
|
|
601
|
+
console.log(`Delete ${k}`);
|
|
493
602
|
deletes[k] = 1;
|
|
494
603
|
}
|
|
495
604
|
}
|
|
@@ -538,7 +647,7 @@ async function diffFromPackage(
|
|
|
538
647
|
|
|
539
648
|
if (!originSource) {
|
|
540
649
|
throw new Error(
|
|
541
|
-
|
|
650
|
+
'Bundle file not found! Please use default bundle file name and path.',
|
|
542
651
|
);
|
|
543
652
|
}
|
|
544
653
|
|
|
@@ -550,11 +659,9 @@ async function diffFromPackage(
|
|
|
550
659
|
zipfile.outputStream.on('error', (err) => {
|
|
551
660
|
throw err;
|
|
552
661
|
});
|
|
553
|
-
zipfile.outputStream
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
resolve();
|
|
557
|
-
});
|
|
662
|
+
zipfile.outputStream.pipe(fs.createWriteStream(output)).on('close', () => {
|
|
663
|
+
resolve();
|
|
664
|
+
});
|
|
558
665
|
});
|
|
559
666
|
|
|
560
667
|
await enumZipEntries(next, (entry, nextZipfile) => {
|
|
@@ -581,7 +688,7 @@ async function diffFromPackage(
|
|
|
581
688
|
);
|
|
582
689
|
//console.log('End diff');
|
|
583
690
|
});
|
|
584
|
-
}else {
|
|
691
|
+
} else {
|
|
585
692
|
// If same file.
|
|
586
693
|
if (originEntries[entry.fileName] === entry.crc32) {
|
|
587
694
|
copies[entry.fileName] = '';
|
|
@@ -594,7 +701,7 @@ async function diffFromPackage(
|
|
|
594
701
|
}
|
|
595
702
|
|
|
596
703
|
return new Promise((resolve, reject) => {
|
|
597
|
-
nextZipfile.openReadStream(entry,
|
|
704
|
+
nextZipfile.openReadStream(entry, (err, readStream) => {
|
|
598
705
|
if (err) {
|
|
599
706
|
return reject(err);
|
|
600
707
|
}
|
|
@@ -630,7 +737,7 @@ export async function enumZipEntries(zipFn, callback, nestedPath = '') {
|
|
|
630
737
|
!entry.fileName.endsWith('/') &&
|
|
631
738
|
entry.fileName.toLowerCase().endsWith('.hap')
|
|
632
739
|
) {
|
|
633
|
-
const tempDir = path.join(os.tmpdir(),
|
|
740
|
+
const tempDir = path.join(os.tmpdir(), `nested_zip_${Date.now()}`);
|
|
634
741
|
await fs.ensureDir(tempDir);
|
|
635
742
|
const tempZipPath = path.join(tempDir, 'temp.zip');
|
|
636
743
|
|
|
@@ -644,7 +751,7 @@ export async function enumZipEntries(zipFn, callback, nestedPath = '') {
|
|
|
644
751
|
});
|
|
645
752
|
});
|
|
646
753
|
|
|
647
|
-
await enumZipEntries(tempZipPath, callback, fullPath
|
|
754
|
+
await enumZipEntries(tempZipPath, callback, `${fullPath}/`);
|
|
648
755
|
|
|
649
756
|
await fs.remove(tempDir);
|
|
650
757
|
}
|
|
@@ -697,7 +804,7 @@ function diffArgsCheck(args, options, diffFn) {
|
|
|
697
804
|
return {
|
|
698
805
|
origin,
|
|
699
806
|
next,
|
|
700
|
-
realOutput: output.replace(/\$\{time\}/g,
|
|
807
|
+
realOutput: output.replace(/\$\{time\}/g, `${Date.now()}`),
|
|
701
808
|
};
|
|
702
809
|
}
|
|
703
810
|
|
|
@@ -707,15 +814,19 @@ export const commands = {
|
|
|
707
814
|
options.platform || (await question('平台(ios/android/harmony):')),
|
|
708
815
|
);
|
|
709
816
|
|
|
710
|
-
|
|
817
|
+
const { bundleName, entryFile, intermediaDir, output, dev } =
|
|
711
818
|
translateOptions({
|
|
712
819
|
...options,
|
|
713
820
|
platform,
|
|
714
821
|
});
|
|
715
822
|
|
|
716
|
-
const
|
|
823
|
+
const bundleParams = await checkPlugins();
|
|
824
|
+
const sourcemap = bundleParams.sourcemap;
|
|
825
|
+
const isSentry = bundleParams.sentry;
|
|
826
|
+
|
|
827
|
+
const sourcemapOutput = path.join(intermediaDir, `${bundleName}.map`);
|
|
717
828
|
|
|
718
|
-
const realOutput = output.replace(/\$\{time\}/g,
|
|
829
|
+
const realOutput = output.replace(/\$\{time\}/g, `${Date.now()}`);
|
|
719
830
|
|
|
720
831
|
if (!platform) {
|
|
721
832
|
throw new Error('Platform must be specified.');
|
|
@@ -723,7 +834,7 @@ export const commands = {
|
|
|
723
834
|
|
|
724
835
|
const { version, major, minor } = getRNVersion();
|
|
725
836
|
|
|
726
|
-
console.log(
|
|
837
|
+
console.log(`Bundling with react-native: ${version}`);
|
|
727
838
|
|
|
728
839
|
await runReactNativeBundleCommand(
|
|
729
840
|
bundleName,
|
|
@@ -738,12 +849,21 @@ export const commands = {
|
|
|
738
849
|
|
|
739
850
|
const v = await question('是否现在上传此热更包?(Y/N)');
|
|
740
851
|
if (v.toLowerCase() === 'y') {
|
|
741
|
-
|
|
852
|
+
const versionName = await this.publish({
|
|
742
853
|
args: [realOutput],
|
|
743
854
|
options: {
|
|
744
855
|
platform,
|
|
745
856
|
},
|
|
746
857
|
});
|
|
858
|
+
if (isSentry) {
|
|
859
|
+
await copyDebugidForSentry(bundleName, intermediaDir, sourcemapOutput);
|
|
860
|
+
await uploadSourcemapForSentry(
|
|
861
|
+
bundleName,
|
|
862
|
+
intermediaDir,
|
|
863
|
+
sourcemapOutput,
|
|
864
|
+
versionName,
|
|
865
|
+
);
|
|
866
|
+
}
|
|
747
867
|
}
|
|
748
868
|
},
|
|
749
869
|
|
|
@@ -817,7 +937,7 @@ export const commands = {
|
|
|
817
937
|
|
|
818
938
|
await diffFromPackage(origin, next, realOutput, 'main.jsbundle', (v) => {
|
|
819
939
|
const m = /^Payload\/[^/]+\/(.+)$/.exec(v);
|
|
820
|
-
return m
|
|
940
|
+
return m?.[1];
|
|
821
941
|
});
|
|
822
942
|
|
|
823
943
|
console.log(`${realOutput} generated.`);
|
|
@@ -832,7 +952,7 @@ export const commands = {
|
|
|
832
952
|
|
|
833
953
|
await diffFromPackage(origin, next, realOutput, 'main.jsbundle', (v) => {
|
|
834
954
|
const m = /^Payload\/[^/]+\/(.+)$/.exec(v);
|
|
835
|
-
return m
|
|
955
|
+
return m?.[1];
|
|
836
956
|
});
|
|
837
957
|
|
|
838
958
|
console.log(`${realOutput} generated.`);
|
|
@@ -6,7 +6,7 @@ import { checkPlatform, getSelectedApp } from './app';
|
|
|
6
6
|
import { getApkInfo, getIpaInfo, getAppInfo } from './utils';
|
|
7
7
|
import Table from 'tty-table';
|
|
8
8
|
|
|
9
|
-
export async function listPackage(appId) {
|
|
9
|
+
export async function listPackage(appId: string) {
|
|
10
10
|
const { data } = await get(`/app/${appId}/package/list?limit=1000`);
|
|
11
11
|
|
|
12
12
|
const header = [{ value: '原生包 Id' }, { value: '原生版本' }];
|
|
@@ -35,12 +35,12 @@ export async function listPackage(appId) {
|
|
|
35
35
|
return data;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
export async function choosePackage(appId) {
|
|
38
|
+
export async function choosePackage(appId: string) {
|
|
39
39
|
const list = await listPackage(appId);
|
|
40
40
|
|
|
41
41
|
while (true) {
|
|
42
42
|
const id = await question('输入原生包 id:');
|
|
43
|
-
const app = list.find((v) => v.id === (id
|
|
43
|
+
const app = list.find((v) => v.id === Number(id));
|
|
44
44
|
if (app) {
|
|
45
45
|
return app;
|
|
46
46
|
}
|
|
@@ -48,7 +48,7 @@ export async function choosePackage(appId) {
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
export const commands = {
|
|
51
|
-
uploadIpa: async
|
|
51
|
+
uploadIpa: async ({ args }: { args: string[] }) => {
|
|
52
52
|
const fn = args[0];
|
|
53
53
|
if (!fn || !fn.endsWith('.ipa')) {
|
|
54
54
|
throw new Error('使用方法: pushy uploadIpa ipa后缀文件');
|
|
@@ -85,7 +85,7 @@ export const commands = {
|
|
|
85
85
|
`已成功上传ipa原生包(id: ${id}, version: ${versionName}, buildTime: ${buildTime})`,
|
|
86
86
|
);
|
|
87
87
|
},
|
|
88
|
-
uploadApk: async
|
|
88
|
+
uploadApk: async ({ args }) => {
|
|
89
89
|
const fn = args[0];
|
|
90
90
|
if (!fn || !fn.endsWith('.apk')) {
|
|
91
91
|
throw new Error('使用方法: pushy uploadApk apk后缀文件');
|
|
@@ -122,7 +122,7 @@ export const commands = {
|
|
|
122
122
|
`已成功上传apk原生包(id: ${id}, version: ${versionName}, buildTime: ${buildTime})`,
|
|
123
123
|
);
|
|
124
124
|
},
|
|
125
|
-
uploadApp: async
|
|
125
|
+
uploadApp: async ({ args }) => {
|
|
126
126
|
const fn = args[0];
|
|
127
127
|
if (!fn || !fn.endsWith('.app')) {
|
|
128
128
|
throw new Error('使用方法: pushy uploadApp app后缀文件');
|
|
@@ -134,7 +134,6 @@ export const commands = {
|
|
|
134
134
|
appKey: appKeyInPkg,
|
|
135
135
|
} = await getAppInfo(fn);
|
|
136
136
|
const { appId, appKey } = await getSelectedApp('harmony');
|
|
137
|
-
|
|
138
137
|
|
|
139
138
|
if (appIdInPkg && appIdInPkg != appId) {
|
|
140
139
|
throw new Error(
|
|
@@ -160,28 +159,28 @@ export const commands = {
|
|
|
160
159
|
`已成功上传app原生包(id: ${id}, version: ${versionName}, buildTime: ${buildTime})`,
|
|
161
160
|
);
|
|
162
161
|
},
|
|
163
|
-
parseApp: async
|
|
162
|
+
parseApp: async ({ args }) => {
|
|
164
163
|
const fn = args[0];
|
|
165
164
|
if (!fn || !fn.endsWith('.app')) {
|
|
166
165
|
throw new Error('使用方法: pushy parseApp app后缀文件');
|
|
167
166
|
}
|
|
168
167
|
console.log(await getAppInfo(fn));
|
|
169
168
|
},
|
|
170
|
-
parseIpa: async
|
|
169
|
+
parseIpa: async ({ args }) => {
|
|
171
170
|
const fn = args[0];
|
|
172
171
|
if (!fn || !fn.endsWith('.ipa')) {
|
|
173
172
|
throw new Error('使用方法: pushy parseIpa ipa后缀文件');
|
|
174
173
|
}
|
|
175
174
|
console.log(await getIpaInfo(fn));
|
|
176
175
|
},
|
|
177
|
-
parseApk: async
|
|
176
|
+
parseApk: async ({ args }) => {
|
|
178
177
|
const fn = args[0];
|
|
179
178
|
if (!fn || !fn.endsWith('.apk')) {
|
|
180
179
|
throw new Error('使用方法: pushy parseApk apk后缀文件');
|
|
181
180
|
}
|
|
182
181
|
console.log(await getApkInfo(fn));
|
|
183
182
|
},
|
|
184
|
-
packages: async
|
|
183
|
+
packages: async ({ options }) => {
|
|
185
184
|
const platform = checkPlatform(
|
|
186
185
|
options.platform || (await question('平台(ios/android/harmony):')),
|
|
187
186
|
);
|