@expo-harmony/cli 55.0.26-harmony.8 → 55.0.26-harmony.9
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 +74 -46
- package/build/bin/expo-harmony.js +1 -1
- package/build/buildHap/build.d.ts +3 -10
- package/build/buildHap/build.js +11 -69
- package/build/buildHap/index.d.ts +2 -0
- package/build/buildHap/index.js +19 -0
- package/build/cli.d.ts +3 -3
- package/build/cli.js +21 -187
- package/build/command.d.ts +9 -0
- package/build/command.js +20 -0
- package/build/doctor/doctor.d.ts +1 -1
- package/build/doctor/doctor.js +64 -56
- package/build/doctor/index.d.ts +2 -0
- package/build/doctor/index.js +16 -0
- package/build/exportEmbed/export.d.ts +2 -2
- package/build/exportEmbed/export.js +53 -49
- package/build/exportEmbed/index.d.ts +2 -0
- package/build/exportEmbed/index.js +19 -0
- package/build/file.d.ts +2 -1
- package/build/file.js +18 -8
- package/build/help.d.ts +1 -0
- package/build/help.js +36 -0
- package/build/index.d.ts +5 -3
- package/build/index.js +6 -5
- package/build/internal/prebuild.d.ts +3 -0
- package/build/internal/prebuild.js +9 -0
- package/build/log.d.ts +4 -0
- package/build/log.js +6 -0
- package/build/modules/index.d.ts +2 -0
- package/build/modules/index.js +16 -0
- package/build/native/bare.d.ts +4 -0
- package/build/native/bare.js +130 -0
- package/build/native/build.d.ts +15 -0
- package/build/native/build.js +67 -0
- package/build/{run → native}/cache.d.ts +2 -2
- package/build/{run → native}/cache.js +8 -8
- package/build/native/hvigor.d.ts +2 -0
- package/build/native/hvigor.js +77 -0
- package/build/native/install.d.ts +5 -0
- package/build/native/install.js +13 -0
- package/build/native/prepareProject.d.ts +11 -0
- package/build/native/prepareProject.js +68 -0
- package/build/native/project.d.ts +8 -0
- package/build/native/project.js +58 -0
- package/build/native/toolchain.d.ts +16 -0
- package/build/{tools.js → native/toolchain.js} +1 -57
- package/build/native/types.d.ts +47 -0
- package/build/native/types.js +2 -0
- package/build/prebuild/check.d.ts +7 -3
- package/build/prebuild/check.js +26 -20
- package/build/prebuild/clean.js +5 -5
- package/build/prebuild/index.d.ts +2 -0
- package/build/prebuild/index.js +51 -0
- package/build/prebuild/prebuild.js +11 -3
- package/build/prebuild/template.js +2 -2
- package/build/process.d.ts +11 -1
- package/build/process.js +16 -0
- package/build/profile.d.ts +1 -0
- package/build/profile.js +12 -0
- package/build/projectLock.js +7 -2
- package/build/run/devices.d.ts +1 -1
- package/build/run/devices.js +15 -10
- package/build/run/emulators.d.ts +1 -1
- package/build/run/emulators.js +2 -5
- package/build/run/index.d.ts +2 -0
- package/build/run/index.js +25 -0
- package/build/run/run.d.ts +4 -10
- package/build/run/run.js +45 -90
- package/build/start/index.d.ts +2 -0
- package/build/start/index.js +33 -0
- package/package.json +14 -4
- package/src/bin/expo-harmony.ts +2 -2
- package/src/buildHap/build.ts +13 -105
- package/src/buildHap/index.ts +19 -0
- package/src/cli.ts +24 -227
- package/src/command.ts +24 -0
- package/src/doctor/doctor.ts +63 -61
- package/src/doctor/index.ts +16 -0
- package/src/exportEmbed/export.ts +64 -55
- package/src/exportEmbed/index.ts +17 -0
- package/src/file.ts +20 -11
- package/src/help.ts +33 -0
- package/src/index.ts +5 -3
- package/src/internal/prebuild.ts +3 -0
- package/src/log.ts +5 -0
- package/src/modules/index.ts +16 -0
- package/src/native/bare.ts +145 -0
- package/src/native/build.ts +81 -0
- package/src/{run → native}/cache.ts +10 -9
- package/src/native/hvigor.ts +81 -0
- package/src/native/install.ts +17 -0
- package/src/native/prepareProject.ts +99 -0
- package/src/native/project.ts +88 -0
- package/src/{tools.ts → native/toolchain.ts} +11 -118
- package/src/native/types.ts +44 -0
- package/src/prebuild/check.ts +30 -19
- package/src/prebuild/clean.ts +3 -3
- package/src/prebuild/index.ts +56 -0
- package/src/prebuild/prebuild.ts +11 -1
- package/src/prebuild/template.ts +2 -2
- package/src/process.ts +38 -1
- package/src/profile.ts +13 -0
- package/src/projectLock.ts +9 -1
- package/src/run/devices.ts +16 -11
- package/src/run/emulators.ts +4 -6
- package/src/run/index.ts +25 -0
- package/src/run/run.ts +56 -129
- package/src/start/index.ts +31 -0
- package/build/buildHap/common.d.ts +0 -24
- package/build/buildHap/common.js +0 -92
- package/build/run/install.d.ts +0 -7
- package/build/run/install.js +0 -26
- package/build/tools.d.ts +0 -39
- package/src/buildHap/common.ts +0 -145
- package/src/run/install.ts +0 -41
package/src/run/run.ts
CHANGED
|
@@ -7,33 +7,18 @@ import {
|
|
|
7
7
|
selectDeviceAsync,
|
|
8
8
|
} from './devices';
|
|
9
9
|
import { HarmonyCliError } from '../errors';
|
|
10
|
-
import {
|
|
11
|
-
import type
|
|
12
|
-
import {
|
|
13
|
-
resolveHarmonyBuildPlanAsync,
|
|
14
|
-
resolveHarmonyEmulator,
|
|
15
|
-
resolveHarmonyToolchain,
|
|
16
|
-
type HarmonyBuildPlan,
|
|
17
|
-
} from '../tools';
|
|
18
|
-
import { installHarmonyDependenciesAsync } from './install';
|
|
10
|
+
import { resolveHarmonyEmulator, resolveHarmonyToolchain } from '../native/toolchain';
|
|
11
|
+
import { type HarmonyBuildPlan } from '../native/types';
|
|
19
12
|
import {
|
|
20
13
|
requireExistingMetroAsync,
|
|
21
14
|
startExpoMetroAsync,
|
|
22
15
|
type MetroSession,
|
|
23
16
|
} from './metro';
|
|
24
|
-
import {
|
|
25
|
-
commitHarmonyNativeBuildCacheAsync,
|
|
26
|
-
prepareHarmonyNativeBuildCacheAsync,
|
|
27
|
-
} from './cache';
|
|
28
|
-
import { toPosixPath } from '../path';
|
|
29
17
|
import { withHarmonyProjectLockAsync } from '../projectLock';
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
runCheckedAsync,
|
|
35
|
-
timed,
|
|
36
|
-
} from '../buildHap/common';
|
|
18
|
+
import { buildNativeAsync, type NativeBuildResult } from '../native/build';
|
|
19
|
+
import { prepareNativeProjectAsync } from '../native/prepareProject';
|
|
20
|
+
import { progress } from '../log';
|
|
21
|
+
import { timedAsync } from '../profile';
|
|
37
22
|
|
|
38
23
|
export interface HarmonyRunOptions {
|
|
39
24
|
appId?: string;
|
|
@@ -47,11 +32,9 @@ export interface HarmonyRunOptions {
|
|
|
47
32
|
variant?: 'debug' | 'release';
|
|
48
33
|
}
|
|
49
34
|
|
|
50
|
-
export interface HarmonyRunResult {
|
|
35
|
+
export interface HarmonyRunResult extends NativeBuildResult {
|
|
51
36
|
bundleName: string;
|
|
52
37
|
device: { id: string; transport: string };
|
|
53
|
-
export: null | { assetCount: number; bundleSha256: string; sourceMapSha256: string };
|
|
54
|
-
hapPath: string;
|
|
55
38
|
installed: boolean;
|
|
56
39
|
launched: true;
|
|
57
40
|
metro: { owner: 'disabled' | 'existing' | 'started'; port: number };
|
|
@@ -62,7 +45,6 @@ export interface HarmonyRunResult {
|
|
|
62
45
|
}
|
|
63
46
|
|
|
64
47
|
interface HarmonyRunSessionOptions extends HarmonyRunOptions {
|
|
65
|
-
/** Give a CLI-started Metro process ownership of the current terminal. */
|
|
66
48
|
interactiveBundler?: boolean;
|
|
67
49
|
}
|
|
68
50
|
|
|
@@ -101,10 +83,10 @@ function resolveRunIdentity(plan: HarmonyBuildPlan, options: NormalizedRunOption
|
|
|
101
83
|
}
|
|
102
84
|
|
|
103
85
|
async function runHarmonyUnlockedAsync(
|
|
104
|
-
|
|
86
|
+
root: string,
|
|
105
87
|
options: HarmonyRunSessionOptions = {}
|
|
106
88
|
): Promise<HarmonyRunSession> {
|
|
107
|
-
const
|
|
89
|
+
const settings: NormalizedRunOptions = {
|
|
108
90
|
appId: options.appId,
|
|
109
91
|
device: options.device,
|
|
110
92
|
interactiveBundler: Boolean(options.interactiveBundler),
|
|
@@ -118,105 +100,52 @@ async function runHarmonyUnlockedAsync(
|
|
|
118
100
|
};
|
|
119
101
|
const steps: Record<string, number> = {};
|
|
120
102
|
|
|
121
|
-
await
|
|
122
|
-
...
|
|
123
|
-
|
|
103
|
+
const plan = await prepareNativeProjectAsync(root, {
|
|
104
|
+
...settings,
|
|
105
|
+
check: false,
|
|
124
106
|
}, steps);
|
|
125
107
|
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
{ buildMode: normalizedOptions.variant }
|
|
129
|
-
));
|
|
130
|
-
const identity = resolveRunIdentity(plan, normalizedOptions);
|
|
131
|
-
const toolchain = resolveHarmonyToolchain();
|
|
108
|
+
const identity = resolveRunIdentity(plan, settings);
|
|
109
|
+
const tools = resolveHarmonyToolchain();
|
|
132
110
|
|
|
133
|
-
progress(
|
|
134
|
-
const device = await
|
|
135
|
-
|
|
136
|
-
|
|
111
|
+
progress(settings, 'Selecting a Harmony device or emulator');
|
|
112
|
+
const device = await timedAsync(steps, 'device', () => selectDeviceAsync(
|
|
113
|
+
tools.hdc,
|
|
114
|
+
settings.device,
|
|
137
115
|
{
|
|
138
116
|
cwd: plan.harmonyRoot,
|
|
139
|
-
emulator: resolveHarmonyEmulator(
|
|
140
|
-
emulatorLogFile: path.join(
|
|
141
|
-
onProgress: message => progress(
|
|
117
|
+
emulator: resolveHarmonyEmulator(tools),
|
|
118
|
+
emulatorLogFile: path.join(root, '.expo', 'harmony', 'emulator.log'),
|
|
119
|
+
onProgress: message => progress(settings, message),
|
|
142
120
|
}
|
|
143
121
|
));
|
|
144
122
|
|
|
145
|
-
|
|
146
|
-
if (normalizedOptions.variant === 'release') {
|
|
147
|
-
progress(normalizedOptions, 'Exporting the release Hermes bundle');
|
|
148
|
-
exportManifest = await timed(steps, 'export', () => exportEmbedAsync(
|
|
149
|
-
projectRoot,
|
|
150
|
-
{ resetCache: normalizedOptions.resetCache, skipDoctor: true }
|
|
151
|
-
));
|
|
152
|
-
} else {
|
|
153
|
-
steps.export = 0;
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
progress(normalizedOptions, 'Installing Harmony project dependencies');
|
|
157
|
-
await timed(steps, 'ohpm', () => installHarmonyDependenciesAsync(plan, toolchain));
|
|
123
|
+
const built = await buildNativeAsync(root, plan, tools, settings, steps);
|
|
158
124
|
|
|
159
125
|
let metro: HarmonyRunSession['metro'] = {
|
|
160
126
|
owner: 'disabled',
|
|
161
|
-
port:
|
|
127
|
+
port: settings.port,
|
|
162
128
|
stop: async () => {},
|
|
163
129
|
waitAsync: async () => {},
|
|
164
130
|
};
|
|
165
|
-
try {
|
|
166
|
-
progress(normalizedOptions, 'Checking Harmony native dependency cache');
|
|
167
|
-
const nativeBuildCache = await timed(steps, 'nativeCache', () => (
|
|
168
|
-
prepareHarmonyNativeBuildCacheAsync(projectRoot, plan)
|
|
169
|
-
));
|
|
170
131
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
progress(normalizedOptions, `Building the ${normalizedOptions.variant} HAP`);
|
|
176
|
-
const buildEnv = {
|
|
177
|
-
...process.env,
|
|
178
|
-
EXPO_HARMONY_NODE: process.env.EXPO_HARMONY_NODE || process.execPath,
|
|
179
|
-
EXPO_METRO_TARGET: 'harmony',
|
|
180
|
-
HERMES_V1_ENABLED: 'true',
|
|
181
|
-
...(normalizedOptions.variant === 'release' ? { EXPO_HARMONY_BUNDLE_PREBUILT: '1' } : {}),
|
|
182
|
-
...(toolchain.sdkHome && !process.env.DEVECO_SDK_HOME
|
|
183
|
-
? { DEVECO_SDK_HOME: toolchain.sdkHome }
|
|
184
|
-
: {}),
|
|
185
|
-
};
|
|
186
|
-
await timed(steps, 'build', () => runCheckedAsync(toolchain.hvigor.command, [
|
|
187
|
-
...toolchain.hvigor.args,
|
|
188
|
-
...plan.hvigorArgs,
|
|
189
|
-
], {
|
|
190
|
-
code: 'ERR_HARMONY_BUILD_FAILED',
|
|
191
|
-
cwd: plan.harmonyRoot,
|
|
192
|
-
env: buildEnv,
|
|
193
|
-
message: 'Hvigor build',
|
|
194
|
-
operation: 'hvigor-build',
|
|
195
|
-
timeoutMs: 15 * 60_000,
|
|
196
|
-
}));
|
|
197
|
-
|
|
198
|
-
if (!isNonEmptyRegularFile(plan.expectedHap)) {
|
|
199
|
-
throw new HarmonyCliError('ERR_HARMONY_HAP_MISSING', 'Hvigor completed without producing the expected non-empty regular HAP.', { operation: 'verify-hap' });
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
await timed(steps, 'nativeCacheCommit', () => commitHarmonyNativeBuildCacheAsync(nativeBuildCache));
|
|
203
|
-
|
|
204
|
-
if (normalizedOptions.variant === 'debug') {
|
|
205
|
-
progress(normalizedOptions, normalizedOptions.noBundler
|
|
132
|
+
try {
|
|
133
|
+
if (settings.variant === 'debug') {
|
|
134
|
+
progress(settings, settings.noBundler
|
|
206
135
|
? 'Connecting to the existing Expo Metro server'
|
|
207
136
|
: 'Starting Expo Metro');
|
|
208
|
-
metro = await
|
|
209
|
-
? requireExistingMetroAsync(
|
|
210
|
-
: startExpoMetroAsync(
|
|
211
|
-
interactive:
|
|
212
|
-
port:
|
|
213
|
-
resetCache:
|
|
137
|
+
metro = await timedAsync(steps, 'metro', () => settings.noBundler
|
|
138
|
+
? requireExistingMetroAsync(settings.port)
|
|
139
|
+
: startExpoMetroAsync(root, {
|
|
140
|
+
interactive: settings.interactiveBundler,
|
|
141
|
+
port: settings.port,
|
|
142
|
+
resetCache: settings.resetCache,
|
|
214
143
|
}));
|
|
215
144
|
|
|
216
|
-
await
|
|
217
|
-
|
|
145
|
+
await timedAsync(steps, 'metroPort', () => configureMetroPortAsync(
|
|
146
|
+
tools.hdc,
|
|
218
147
|
device,
|
|
219
|
-
|
|
148
|
+
settings.port,
|
|
220
149
|
{ cwd: plan.harmonyRoot }
|
|
221
150
|
));
|
|
222
151
|
} else {
|
|
@@ -224,21 +153,21 @@ async function runHarmonyUnlockedAsync(
|
|
|
224
153
|
steps.metroPort = 0;
|
|
225
154
|
}
|
|
226
155
|
|
|
227
|
-
if (
|
|
156
|
+
if (settings.noInstall) {
|
|
228
157
|
steps.install = 0;
|
|
229
158
|
} else {
|
|
230
|
-
progress(
|
|
231
|
-
await
|
|
232
|
-
|
|
159
|
+
progress(settings, `Installing the HAP on ${device.id}`);
|
|
160
|
+
await timedAsync(steps, 'install', () => installHapAsync(
|
|
161
|
+
tools.hdc,
|
|
233
162
|
device,
|
|
234
163
|
plan.expectedHap,
|
|
235
164
|
{ cwd: plan.harmonyRoot }
|
|
236
165
|
));
|
|
237
166
|
}
|
|
238
167
|
|
|
239
|
-
progress(
|
|
240
|
-
await
|
|
241
|
-
|
|
168
|
+
progress(settings, `Launching ${identity.bundleName}`);
|
|
169
|
+
await timedAsync(steps, 'launch', () => launchAppAsync(
|
|
170
|
+
tools.hdc,
|
|
242
171
|
device,
|
|
243
172
|
identity.bundleName,
|
|
244
173
|
identity.abilityName,
|
|
@@ -251,15 +180,8 @@ async function runHarmonyUnlockedAsync(
|
|
|
251
180
|
id: device.id,
|
|
252
181
|
transport: device.transport,
|
|
253
182
|
},
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
assetCount: exportManifest.assets.length,
|
|
257
|
-
bundleSha256: exportManifest.bundle.sha256,
|
|
258
|
-
sourceMapSha256: exportManifest.sourceMap.sha256,
|
|
259
|
-
}
|
|
260
|
-
: null,
|
|
261
|
-
hapPath: toPosixPath(path.relative(projectRoot, plan.expectedHap)),
|
|
262
|
-
installed: !normalizedOptions.noInstall,
|
|
183
|
+
...built,
|
|
184
|
+
installed: !settings.noInstall,
|
|
263
185
|
launched: true,
|
|
264
186
|
metro: {
|
|
265
187
|
owner: metro.owner,
|
|
@@ -268,32 +190,37 @@ async function runHarmonyUnlockedAsync(
|
|
|
268
190
|
ok: true,
|
|
269
191
|
schemaVersion: 1,
|
|
270
192
|
steps,
|
|
271
|
-
variant:
|
|
193
|
+
variant: settings.variant,
|
|
272
194
|
};
|
|
273
195
|
|
|
274
196
|
return { metro, result };
|
|
275
197
|
} catch (error) {
|
|
276
198
|
await metro.stop();
|
|
277
|
-
|
|
199
|
+
|
|
200
|
+
throw new HarmonyCliError(error?.code || 'ERR_HARMONY_UNKNOWN', error?.message || 'Harmony run failed.', {
|
|
201
|
+
cause: error,
|
|
202
|
+
exitCode: error?.exitCode,
|
|
203
|
+
operation: error?.operation,
|
|
204
|
+
});
|
|
278
205
|
}
|
|
279
206
|
}
|
|
280
207
|
|
|
281
208
|
async function runHarmonySessionAsync(
|
|
282
|
-
|
|
209
|
+
root: string,
|
|
283
210
|
options: HarmonyRunSessionOptions = {}
|
|
284
211
|
): Promise<HarmonyRunSession> {
|
|
285
212
|
return withHarmonyProjectLockAsync(
|
|
286
|
-
|
|
213
|
+
root,
|
|
287
214
|
'run',
|
|
288
|
-
() => runHarmonyUnlockedAsync(
|
|
215
|
+
() => runHarmonyUnlockedAsync(root, options)
|
|
289
216
|
);
|
|
290
217
|
}
|
|
291
218
|
|
|
292
219
|
async function runHarmonyAsync(
|
|
293
|
-
|
|
220
|
+
root: string,
|
|
294
221
|
options: HarmonyRunOptions = {}
|
|
295
222
|
): Promise<HarmonyRunResult> {
|
|
296
|
-
const session = await runHarmonySessionAsync(
|
|
223
|
+
const session = await runHarmonySessionAsync(root, options);
|
|
297
224
|
|
|
298
225
|
try {
|
|
299
226
|
return session.result;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { parseCommandArgs, type Command } from '../command';
|
|
2
|
+
import { parseStartArgs } from './options';
|
|
3
|
+
|
|
4
|
+
export const command: Command = async (argv, io) => {
|
|
5
|
+
const args = parseCommandArgs(parseStartArgs, argv, io);
|
|
6
|
+
if (!args) return 0;
|
|
7
|
+
|
|
8
|
+
const { projectRoot: root, options } = args;
|
|
9
|
+
const { startExpoMetroAsync } = await import('../run/metro.js');
|
|
10
|
+
|
|
11
|
+
const metro = await startExpoMetroAsync(root, {
|
|
12
|
+
...options,
|
|
13
|
+
interactive: true,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
if (metro.owner === 'existing') {
|
|
18
|
+
io.log(`Expo Metro is already running on port ${metro.port}.`);
|
|
19
|
+
if (options.resetCache) {
|
|
20
|
+
io.warn('Stop the existing Metro server and run this command again to reset its cache.');
|
|
21
|
+
}
|
|
22
|
+
} else {
|
|
23
|
+
io.log('\n› Logs for your project will appear below. Press Ctrl+C to exit.');
|
|
24
|
+
await metro.waitAsync();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return 0;
|
|
28
|
+
} finally {
|
|
29
|
+
await metro.stop();
|
|
30
|
+
}
|
|
31
|
+
};
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
interface HarmonyBuildPipelineOptions {
|
|
2
|
-
io?: Pick<Console, 'error' | 'log' | 'warn'>;
|
|
3
|
-
requireDeviceTools?: boolean;
|
|
4
|
-
/** @internal Reuse the native project without an isolated drift check. */
|
|
5
|
-
skipGeneratedProjectCheck?: boolean;
|
|
6
|
-
sync: boolean;
|
|
7
|
-
variant: 'debug' | 'release';
|
|
8
|
-
}
|
|
9
|
-
interface CheckedProcessOptions {
|
|
10
|
-
code: string;
|
|
11
|
-
cwd: string;
|
|
12
|
-
env?: NodeJS.ProcessEnv;
|
|
13
|
-
message: string;
|
|
14
|
-
operation: string;
|
|
15
|
-
outputLimit?: number;
|
|
16
|
-
timeoutMs?: number;
|
|
17
|
-
}
|
|
18
|
-
declare function progress(options: HarmonyBuildPipelineOptions, message: string): void;
|
|
19
|
-
declare function timed<T>(steps: Record<string, number>, name: string, operation: () => Promise<T> | T): Promise<T>;
|
|
20
|
-
declare function isNonEmptyRegularFile(file: string): boolean;
|
|
21
|
-
declare function runCheckedAsync(command: string, args: string[], options: CheckedProcessOptions): Promise<import("../process").ProcessResult>;
|
|
22
|
-
declare function ensureGeneratedProjectAsync(projectRoot: string, options: HarmonyBuildPipelineOptions, steps: Record<string, number>): Promise<void>;
|
|
23
|
-
export { ensureGeneratedProjectAsync, isNonEmptyRegularFile, progress, runCheckedAsync, timed, };
|
|
24
|
-
export type { CheckedProcessOptions, HarmonyBuildPipelineOptions };
|
package/build/buildHap/common.js
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.ensureGeneratedProjectAsync = ensureGeneratedProjectAsync;
|
|
7
|
-
exports.isNonEmptyRegularFile = isNonEmptyRegularFile;
|
|
8
|
-
exports.progress = progress;
|
|
9
|
-
exports.runCheckedAsync = runCheckedAsync;
|
|
10
|
-
exports.timed = timed;
|
|
11
|
-
const node_fs_1 = __importDefault(require("node:fs"));
|
|
12
|
-
const doctor_1 = require("../doctor/doctor");
|
|
13
|
-
const errors_1 = require("../errors");
|
|
14
|
-
const check_1 = require("../prebuild/check");
|
|
15
|
-
const prebuild_1 = require("../prebuild/prebuild");
|
|
16
|
-
const process_1 = require("../process");
|
|
17
|
-
const tools_1 = require("../tools");
|
|
18
|
-
function progress(options, message) {
|
|
19
|
-
options.io?.log?.(`› ${message}`);
|
|
20
|
-
}
|
|
21
|
-
async function timed(steps, name, operation) {
|
|
22
|
-
const started = performance.now();
|
|
23
|
-
try {
|
|
24
|
-
return await operation();
|
|
25
|
-
}
|
|
26
|
-
finally {
|
|
27
|
-
steps[name] = Math.max(0, Math.round(performance.now() - started));
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
function assertDoctor(result) {
|
|
31
|
-
if (result.ok)
|
|
32
|
-
return;
|
|
33
|
-
const failing = result.checks.filter(check => check.status === 'error').map(check => check.id);
|
|
34
|
-
throw new errors_1.HarmonyCliError('ERR_HARMONY_DOCTOR_FAILED', `Harmony doctor found blocking checks: ${failing.join(', ') || 'unknown'}.`, { operation: 'doctor' });
|
|
35
|
-
}
|
|
36
|
-
function isNonEmptyRegularFile(file) {
|
|
37
|
-
try {
|
|
38
|
-
const stat = node_fs_1.default.lstatSync(file);
|
|
39
|
-
return !stat.isSymbolicLink() && stat.isFile() && stat.size > 0;
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
async function runCheckedAsync(command, args, options) {
|
|
46
|
-
const result = await (0, process_1.spawnAsync)(command, args, {
|
|
47
|
-
capture: true,
|
|
48
|
-
cwd: options.cwd,
|
|
49
|
-
env: options.env,
|
|
50
|
-
operation: options.operation,
|
|
51
|
-
outputLimit: options.outputLimit || 2 * 1024 * 1024,
|
|
52
|
-
timeoutMs: options.timeoutMs,
|
|
53
|
-
});
|
|
54
|
-
if (result.code !== 0 || result.timedOut) {
|
|
55
|
-
const diagnostics = (0, process_1.formatDiagnostics)(result);
|
|
56
|
-
throw new errors_1.HarmonyCliError(options.code, `${options.message} exited with code ${result.code}${result.timedOut ? ' after timing out' : ''}.${diagnostics ? `\n${diagnostics}` : ''}`, { exitCode: result.code || 1, operation: options.operation });
|
|
57
|
-
}
|
|
58
|
-
return result;
|
|
59
|
-
}
|
|
60
|
-
async function ensureGeneratedProjectAsync(projectRoot, options, steps) {
|
|
61
|
-
const plan = await (0, tools_1.resolveHarmonyBuildPlanIfPresentAsync)(projectRoot, {
|
|
62
|
-
buildMode: options.variant,
|
|
63
|
-
});
|
|
64
|
-
const exists = Boolean(plan && node_fs_1.default.existsSync(plan.harmonyRoot));
|
|
65
|
-
progress(options, 'Checking the Harmony project');
|
|
66
|
-
const doctor = await timed(steps, 'doctor', () => (0, doctor_1.doctorAsync)(projectRoot, {
|
|
67
|
-
requireBuildTools: true,
|
|
68
|
-
requireDeviceTools: options.requireDeviceTools,
|
|
69
|
-
validateGeneratedProject: exists,
|
|
70
|
-
validateModules: false,
|
|
71
|
-
}));
|
|
72
|
-
assertDoctor(doctor);
|
|
73
|
-
if (!exists || options.sync) {
|
|
74
|
-
progress(options, exists
|
|
75
|
-
? 'Synchronizing the generated Harmony project'
|
|
76
|
-
: 'Generating the missing Harmony project');
|
|
77
|
-
await timed(steps, 'prebuild', () => (0, prebuild_1.prebuildParsedAsync)(projectRoot, [], { buildType: options.variant }));
|
|
78
|
-
steps.cngCheck = 0;
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
steps.prebuild = 0;
|
|
82
|
-
if (options.skipGeneratedProjectCheck) {
|
|
83
|
-
steps.cngCheck = 0;
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
progress(options, 'Checking CNG ownership and drift');
|
|
87
|
-
const check = await timed(steps, 'cngCheck', () => (0, check_1.checkAsync)(projectRoot, { buildType: options.variant }));
|
|
88
|
-
if (!check.clean) {
|
|
89
|
-
const summary = check.changes.slice(0, 8).map(change => `${change.type}:${change.path}`).join(', ');
|
|
90
|
-
throw new errors_1.HarmonyCliError('ERR_HARMONY_MANIFEST_DRIFT', `Generated Harmony files differ from CNG desired state${summary ? ` (${summary})` : ''}. Run expo-harmony prebuild or retry with --sync.`, { operation: 'check' });
|
|
91
|
-
}
|
|
92
|
-
}
|
package/build/run/install.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { HarmonyBuildPlan, HarmonyToolchain } from '../tools';
|
|
2
|
-
interface InstallOptions {
|
|
3
|
-
timeoutMs?: number;
|
|
4
|
-
}
|
|
5
|
-
/** Runs OHPM against the generated project without rewriting its manifest. */
|
|
6
|
-
declare function installHarmonyDependenciesAsync(plan: HarmonyBuildPlan, toolchain: HarmonyToolchain, options?: InstallOptions): Promise<void>;
|
|
7
|
-
export { installHarmonyDependenciesAsync };
|
package/build/run/install.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.installHarmonyDependenciesAsync = installHarmonyDependenciesAsync;
|
|
4
|
-
const errors_1 = require("../errors");
|
|
5
|
-
const process_1 = require("../process");
|
|
6
|
-
function installMessage(result) {
|
|
7
|
-
const diagnostics = (0, process_1.formatDiagnostics)(result);
|
|
8
|
-
return `OHPM install exited with code ${result.code}${result.timedOut ? ' after timing out' : ''}.`
|
|
9
|
-
+ `${diagnostics ? `\n${diagnostics}` : ''}`;
|
|
10
|
-
}
|
|
11
|
-
/** Runs OHPM against the generated project without rewriting its manifest. */
|
|
12
|
-
async function installHarmonyDependenciesAsync(plan, toolchain, options = {}) {
|
|
13
|
-
const result = await (0, process_1.spawnAsync)(toolchain.ohpm.command, [...toolchain.ohpm.args, 'install', '--all'], {
|
|
14
|
-
capture: true,
|
|
15
|
-
cwd: plan.harmonyRoot,
|
|
16
|
-
operation: 'ohpm-install',
|
|
17
|
-
outputLimit: 2 * 1024 * 1024,
|
|
18
|
-
timeoutMs: options.timeoutMs || 5 * 60_000,
|
|
19
|
-
});
|
|
20
|
-
if (result.code !== 0 || result.timedOut) {
|
|
21
|
-
throw new errors_1.HarmonyCliError('ERR_HARMONY_OHPM_FAILED', installMessage(result), {
|
|
22
|
-
exitCode: result.code || 1,
|
|
23
|
-
operation: 'ohpm-install',
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
}
|
package/build/tools.d.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { type HarmonyBuildDescriptor } from '@expo-harmony/prebuild-config/build-descriptor';
|
|
2
|
-
export interface HarmonyTool {
|
|
3
|
-
args: string[];
|
|
4
|
-
command: string;
|
|
5
|
-
source: 'deveco' | 'override' | 'path';
|
|
6
|
-
}
|
|
7
|
-
export interface HarmonyToolchain {
|
|
8
|
-
hdc: HarmonyTool;
|
|
9
|
-
hvigor: HarmonyTool;
|
|
10
|
-
ohpm: HarmonyTool;
|
|
11
|
-
sdkHome: string | null;
|
|
12
|
-
toolsRoot: string | null;
|
|
13
|
-
}
|
|
14
|
-
export interface HarmonyBuildPlan {
|
|
15
|
-
abilityName: string;
|
|
16
|
-
buildMode: 'debug' | 'release';
|
|
17
|
-
bundleName: string;
|
|
18
|
-
expectedHap: string;
|
|
19
|
-
exportPaths: HarmonyBuildDescriptor['export'];
|
|
20
|
-
harmonyRoot: string;
|
|
21
|
-
hvigorArgs: string[];
|
|
22
|
-
moduleName: string;
|
|
23
|
-
moduleRoot: string;
|
|
24
|
-
nativeCache: HarmonyBuildDescriptor['nativeCache'];
|
|
25
|
-
nativeInputs: HarmonyBuildDescriptor['nativeInputs'];
|
|
26
|
-
projectFiles: HarmonyBuildDescriptor['projectFiles'];
|
|
27
|
-
productName: string;
|
|
28
|
-
targetName: string;
|
|
29
|
-
}
|
|
30
|
-
declare function resolveHarmonyToolchain(): HarmonyToolchain;
|
|
31
|
-
declare function createHarmonyToolchainEnv(toolchain?: HarmonyToolchain): NodeJS.ProcessEnv;
|
|
32
|
-
declare function resolveHarmonyEmulator(toolchain: HarmonyToolchain): HarmonyTool;
|
|
33
|
-
declare function resolveHarmonyBuildPlanIfPresentAsync(projectRoot: string, options?: {
|
|
34
|
-
buildMode?: 'debug' | 'release';
|
|
35
|
-
}): Promise<HarmonyBuildPlan | null>;
|
|
36
|
-
declare function resolveHarmonyBuildPlanAsync(projectRoot: string, options?: {
|
|
37
|
-
buildMode?: 'debug' | 'release';
|
|
38
|
-
}): Promise<HarmonyBuildPlan>;
|
|
39
|
-
export { createHarmonyToolchainEnv, resolveHarmonyBuildPlanAsync, resolveHarmonyBuildPlanIfPresentAsync, resolveHarmonyEmulator, resolveHarmonyToolchain, };
|
package/src/buildHap/common.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
|
|
3
|
-
import { doctorAsync, type DoctorResult } from '../doctor/doctor';
|
|
4
|
-
import { HarmonyCliError } from '../errors';
|
|
5
|
-
import { checkAsync } from '../prebuild/check';
|
|
6
|
-
import { prebuildParsedAsync } from '../prebuild/prebuild';
|
|
7
|
-
import { formatDiagnostics, spawnAsync } from '../process';
|
|
8
|
-
import { resolveHarmonyBuildPlanIfPresentAsync } from '../tools';
|
|
9
|
-
|
|
10
|
-
interface HarmonyBuildPipelineOptions {
|
|
11
|
-
io?: Pick<Console, 'error' | 'log' | 'warn'>;
|
|
12
|
-
requireDeviceTools?: boolean;
|
|
13
|
-
/** @internal Reuse the native project without an isolated drift check. */
|
|
14
|
-
skipGeneratedProjectCheck?: boolean;
|
|
15
|
-
sync: boolean;
|
|
16
|
-
variant: 'debug' | 'release';
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
interface CheckedProcessOptions {
|
|
20
|
-
code: string;
|
|
21
|
-
cwd: string;
|
|
22
|
-
env?: NodeJS.ProcessEnv;
|
|
23
|
-
message: string;
|
|
24
|
-
operation: string;
|
|
25
|
-
outputLimit?: number;
|
|
26
|
-
timeoutMs?: number;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function progress(options: HarmonyBuildPipelineOptions, message: string): void {
|
|
30
|
-
options.io?.log?.(`› ${message}`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function timed<T>(
|
|
34
|
-
steps: Record<string, number>,
|
|
35
|
-
name: string,
|
|
36
|
-
operation: () => Promise<T> | T
|
|
37
|
-
): Promise<T> {
|
|
38
|
-
const started = performance.now();
|
|
39
|
-
try {
|
|
40
|
-
return await operation();
|
|
41
|
-
} finally {
|
|
42
|
-
steps[name] = Math.max(0, Math.round(performance.now() - started));
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function assertDoctor(result: DoctorResult): void {
|
|
47
|
-
if (result.ok) return;
|
|
48
|
-
|
|
49
|
-
const failing = result.checks.filter(check => check.status === 'error').map(check => check.id);
|
|
50
|
-
|
|
51
|
-
throw new HarmonyCliError('ERR_HARMONY_DOCTOR_FAILED', `Harmony doctor found blocking checks: ${failing.join(', ') || 'unknown'}.`, { operation: 'doctor' });
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function isNonEmptyRegularFile(file: string): boolean {
|
|
55
|
-
try {
|
|
56
|
-
const stat = fs.lstatSync(file);
|
|
57
|
-
return !stat.isSymbolicLink() && stat.isFile() && stat.size > 0;
|
|
58
|
-
} catch {
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async function runCheckedAsync(
|
|
64
|
-
command: string,
|
|
65
|
-
args: string[],
|
|
66
|
-
options: CheckedProcessOptions
|
|
67
|
-
) {
|
|
68
|
-
const result = await spawnAsync(command, args, {
|
|
69
|
-
capture: true,
|
|
70
|
-
cwd: options.cwd,
|
|
71
|
-
env: options.env,
|
|
72
|
-
operation: options.operation,
|
|
73
|
-
outputLimit: options.outputLimit || 2 * 1024 * 1024,
|
|
74
|
-
timeoutMs: options.timeoutMs,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
if (result.code !== 0 || result.timedOut) {
|
|
78
|
-
const diagnostics = formatDiagnostics(result);
|
|
79
|
-
throw new HarmonyCliError(
|
|
80
|
-
options.code,
|
|
81
|
-
`${options.message} exited with code ${result.code}${result.timedOut ? ' after timing out' : ''}.${diagnostics ? `\n${diagnostics}` : ''}`,
|
|
82
|
-
{ exitCode: result.code || 1, operation: options.operation }
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return result;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
async function ensureGeneratedProjectAsync(
|
|
90
|
-
projectRoot: string,
|
|
91
|
-
options: HarmonyBuildPipelineOptions,
|
|
92
|
-
steps: Record<string, number>
|
|
93
|
-
) {
|
|
94
|
-
const plan = await resolveHarmonyBuildPlanIfPresentAsync(projectRoot, {
|
|
95
|
-
buildMode: options.variant,
|
|
96
|
-
});
|
|
97
|
-
const exists = Boolean(plan && fs.existsSync(plan.harmonyRoot));
|
|
98
|
-
|
|
99
|
-
progress(options, 'Checking the Harmony project');
|
|
100
|
-
const doctor = await timed(steps, 'doctor', () => doctorAsync(projectRoot, {
|
|
101
|
-
requireBuildTools: true,
|
|
102
|
-
requireDeviceTools: options.requireDeviceTools,
|
|
103
|
-
validateGeneratedProject: exists,
|
|
104
|
-
validateModules: false,
|
|
105
|
-
}));
|
|
106
|
-
assertDoctor(doctor);
|
|
107
|
-
|
|
108
|
-
if (!exists || options.sync) {
|
|
109
|
-
progress(options, exists
|
|
110
|
-
? 'Synchronizing the generated Harmony project'
|
|
111
|
-
: 'Generating the missing Harmony project');
|
|
112
|
-
await timed(steps, 'prebuild', () => prebuildParsedAsync(
|
|
113
|
-
projectRoot,
|
|
114
|
-
[],
|
|
115
|
-
{ buildType: options.variant }
|
|
116
|
-
));
|
|
117
|
-
steps.cngCheck = 0;
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
steps.prebuild = 0;
|
|
122
|
-
if (options.skipGeneratedProjectCheck) {
|
|
123
|
-
steps.cngCheck = 0;
|
|
124
|
-
return;
|
|
125
|
-
}
|
|
126
|
-
progress(options, 'Checking CNG ownership and drift');
|
|
127
|
-
const check = await timed(steps, 'cngCheck', () => checkAsync(projectRoot, { buildType: options.variant }));
|
|
128
|
-
if (!check.clean) {
|
|
129
|
-
const summary = check.changes.slice(0, 8).map(change => `${change.type}:${change.path}`).join(', ');
|
|
130
|
-
throw new HarmonyCliError(
|
|
131
|
-
'ERR_HARMONY_MANIFEST_DRIFT',
|
|
132
|
-
`Generated Harmony files differ from CNG desired state${summary ? ` (${summary})` : ''}. Run expo-harmony prebuild or retry with --sync.`,
|
|
133
|
-
{ operation: 'check' }
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
export {
|
|
139
|
-
ensureGeneratedProjectAsync,
|
|
140
|
-
isNonEmptyRegularFile,
|
|
141
|
-
progress,
|
|
142
|
-
runCheckedAsync,
|
|
143
|
-
timed,
|
|
144
|
-
};
|
|
145
|
-
export type { CheckedProcessOptions, HarmonyBuildPipelineOptions };
|