@expo-harmony/cli 55.0.26-harmony.1 → 55.0.26-harmony.11
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 +87 -38
- package/build/args.d.ts +19 -0
- package/build/args.js +27 -0
- package/build/bin/expo-harmony.d.ts +2 -0
- package/build/bin/expo-harmony.js +1 -1
- package/build/buildHap/build.d.ts +18 -0
- package/build/buildHap/build.js +38 -0
- package/build/buildHap/index.d.ts +2 -0
- package/build/buildHap/index.js +19 -0
- package/build/buildHap/options.d.ts +7 -0
- package/build/buildHap/options.js +30 -0
- package/build/cli.d.ts +3 -0
- package/build/cli.js +40 -0
- package/build/command.d.ts +9 -0
- package/build/command.js +20 -0
- package/build/development/manifest.d.ts +1 -0
- package/build/development/manifest.js +121 -0
- package/build/development/protocol.d.ts +3 -0
- package/build/development/protocol.js +33 -0
- package/build/development/session.d.ts +5 -0
- package/build/development/session.js +66 -0
- package/build/doctor/doctor.d.ts +20 -0
- package/build/doctor/doctor.js +226 -0
- package/build/doctor/index.d.ts +2 -0
- package/build/doctor/index.js +16 -0
- package/build/doctor/options.d.ts +5 -0
- package/build/doctor/options.js +15 -0
- package/build/entry.d.ts +2 -0
- package/build/entry.js +47 -0
- package/build/errors.d.ts +12 -0
- package/build/errors.js +16 -0
- package/build/expo.d.ts +19 -0
- package/build/expo.js +53 -0
- package/build/exportEmbed/export.d.ts +18 -0
- package/build/exportEmbed/export.js +124 -0
- package/build/exportEmbed/index.d.ts +2 -0
- package/build/exportEmbed/index.js +19 -0
- package/build/exportEmbed/manifest.d.ts +44 -0
- package/build/exportEmbed/manifest.js +171 -0
- package/build/exportEmbed/options.d.ts +7 -0
- package/build/exportEmbed/options.js +22 -0
- package/build/file.d.ts +10 -0
- package/build/file.js +110 -0
- package/build/help.d.ts +1 -0
- package/build/help.js +44 -0
- package/build/index.d.ts +14 -0
- package/build/index.js +6 -5
- package/build/internal/development.d.ts +1 -0
- package/build/internal/development.js +8 -0
- package/build/internal/export.d.ts +1 -0
- package/build/internal/export.js +80 -0
- 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/modules/modules.d.ts +42 -0
- package/build/modules/modules.js +84 -0
- package/build/modules/options.d.ts +10 -0
- package/build/modules/options.js +45 -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 +69 -0
- package/build/native/cache.d.ts +11 -0
- package/build/native/cache.js +73 -0
- package/build/native/hvigor.d.ts +3 -0
- package/build/native/hvigor.js +83 -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/native/toolchain.js +172 -0
- package/build/native/types.d.ts +47 -0
- package/build/native/types.js +2 -0
- package/build/path.d.ts +4 -0
- package/build/path.js +27 -0
- package/build/prebuild/check.d.ts +10 -0
- package/build/prebuild/check.js +151 -0
- package/build/prebuild/clean.d.ts +2 -0
- package/build/prebuild/clean.js +50 -0
- package/build/prebuild/index.d.ts +2 -0
- package/build/prebuild/index.js +51 -0
- package/build/prebuild/options.d.ts +10 -0
- package/build/prebuild/options.js +50 -0
- package/build/prebuild/prebuild.d.ts +6 -0
- package/build/prebuild/prebuild.js +70 -0
- package/build/prebuild/template.d.ts +8 -0
- package/build/prebuild/template.js +86 -0
- package/build/process.d.ts +41 -0
- package/build/process.js +324 -0
- package/build/profile.d.ts +1 -0
- package/build/profile.js +12 -0
- package/build/project.d.ts +2 -0
- package/build/project.js +23 -0
- package/build/projectLock.d.ts +2 -0
- package/build/projectLock.js +185 -0
- package/build/run/devices.d.ts +29 -0
- package/build/run/devices.js +223 -0
- package/build/run/emulators.d.ts +13 -0
- package/build/run/emulators.js +82 -0
- package/build/run/index.d.ts +2 -0
- package/build/run/index.js +25 -0
- package/build/run/metro.d.ts +21 -0
- package/build/run/metro.js +162 -0
- package/build/run/options.d.ts +14 -0
- package/build/run/options.js +62 -0
- package/build/run/run.d.ts +46 -0
- package/build/run/run.js +135 -0
- package/build/runtime/config.d.ts +37 -0
- package/build/runtime/config.js +169 -0
- package/build/runtime/contract.d.ts +5 -0
- package/build/runtime/contract.js +109 -0
- package/build/runtime/fingerprint.d.ts +1 -0
- package/build/runtime/fingerprint.js +49 -0
- package/build/runtime/index.d.ts +2 -0
- package/build/runtime/index.js +50 -0
- package/build/start/index.d.ts +2 -0
- package/build/start/index.js +38 -0
- package/build/start/options.d.ts +9 -0
- package/build/start/options.js +38 -0
- package/build/updates/export.d.ts +14 -0
- package/build/updates/export.js +46 -0
- package/build/updates/index.d.ts +2 -0
- package/build/updates/index.js +96 -0
- package/build/upstream.d.ts +9 -0
- package/build/upstream.js +17 -0
- package/package.json +21 -5
- 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 +27 -225
- package/src/command.ts +24 -0
- package/src/development/manifest.ts +127 -0
- package/src/development/protocol.ts +42 -0
- package/src/development/session.ts +83 -0
- package/src/doctor/doctor.ts +67 -62
- package/src/doctor/index.ts +16 -0
- package/src/exportEmbed/export.ts +73 -72
- package/src/exportEmbed/index.ts +17 -0
- package/src/file.ts +20 -11
- package/src/help.ts +41 -0
- package/src/index.ts +5 -3
- package/src/internal/development.ts +8 -0
- package/src/internal/export.ts +82 -0
- 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 +83 -0
- package/src/{run → native}/cache.ts +10 -9
- package/src/native/hvigor.ts +88 -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} +38 -140
- package/src/native/types.ts +44 -0
- package/src/prebuild/check.ts +56 -31
- 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 +175 -64
- package/src/profile.ts +13 -0
- package/src/projectLock.ts +9 -1
- package/src/run/devices.ts +24 -11
- package/src/run/emulators.ts +4 -6
- package/src/run/index.ts +25 -0
- package/src/run/metro.ts +10 -1
- package/src/run/options.ts +2 -0
- package/src/run/run.ts +63 -129
- package/src/runtime/config.ts +207 -0
- package/src/runtime/contract.ts +167 -0
- package/src/runtime/fingerprint.ts +49 -0
- package/src/runtime/index.ts +54 -0
- package/src/start/index.ts +37 -0
- package/src/start/options.ts +12 -0
- package/src/updates/export.ts +60 -0
- package/src/updates/index.ts +89 -0
- package/src/buildHap/common.ts +0 -145
- package/src/run/install.ts +0 -41
|
@@ -0,0 +1,83 @@
|
|
|
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.prepareHarmonyNativeBuild = prepareHarmonyNativeBuild;
|
|
7
|
+
exports.bundleHarmonyNativeBuild = bundleHarmonyNativeBuild;
|
|
8
|
+
exports.publishHarmonyNativeRuntime = publishHarmonyNativeRuntime;
|
|
9
|
+
const node_crypto_1 = __importDefault(require("node:crypto"));
|
|
10
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
11
|
+
const node_module_1 = require("node:module");
|
|
12
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
13
|
+
const node_child_process_1 = require("node:child_process");
|
|
14
|
+
const native_inputs_1 = require("@expo-harmony/config-plugins/internal/native-inputs");
|
|
15
|
+
const errors_1 = require("../errors");
|
|
16
|
+
const toolchain_1 = require("./toolchain");
|
|
17
|
+
function nodeExecutable() {
|
|
18
|
+
const candidates = process.env.EXPO_HARMONY_NODE
|
|
19
|
+
? [process.env.EXPO_HARMONY_NODE]
|
|
20
|
+
: [
|
|
21
|
+
process.execPath,
|
|
22
|
+
...(process.env.PATH || '').split(node_path_1.default.delimiter).filter(Boolean)
|
|
23
|
+
.map(directory => node_path_1.default.join(directory, process.platform === 'win32' ? 'node.exe' : 'node')),
|
|
24
|
+
];
|
|
25
|
+
for (const candidate of new Set(candidates)) {
|
|
26
|
+
const result = (0, node_child_process_1.spawnSync)(candidate, ['-p', 'process.versions.node'], { encoding: 'utf8', timeout: 5_000 });
|
|
27
|
+
if (result.status === 0 && Number.parseInt(result.stdout, 10) >= 20)
|
|
28
|
+
return candidate;
|
|
29
|
+
}
|
|
30
|
+
throw new errors_1.HarmonyCliError('ERR_HARMONY_NODE', 'Harmony native builds require Node.js 20 or newer. Set EXPO_HARMONY_NODE to its executable.', { operation: 'native-build' });
|
|
31
|
+
}
|
|
32
|
+
function run(command, args, cwd) {
|
|
33
|
+
const result = (0, node_child_process_1.spawnSync)(command, args, {
|
|
34
|
+
cwd,
|
|
35
|
+
env: { ...(0, toolchain_1.createHarmonyToolchainEnv)(), EXPO_HARMONY: '1', EXPO_METRO_TARGET: 'harmony', HERMES_V1_ENABLED: 'true' },
|
|
36
|
+
stdio: 'inherit',
|
|
37
|
+
timeout: 10 * 60_000,
|
|
38
|
+
});
|
|
39
|
+
if (result.error || result.status !== 0) {
|
|
40
|
+
throw new errors_1.HarmonyCliError('ERR_HARMONY_NATIVE_BUILD', `Harmony build command failed: ${command} (${result.error?.message || result.status}).`, { cause: result.error, exitCode: result.status || 1, operation: 'native-build' });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Hvigor configuration is synchronous; linking must finish before task execution.
|
|
44
|
+
function prepareHarmonyNativeBuild(root, mode) {
|
|
45
|
+
const harmony = node_path_1.default.join(root, 'harmony');
|
|
46
|
+
if (process.env.EXPO_HARMONY_NATIVE_PREPARED !== '1') {
|
|
47
|
+
const require = (0, node_module_1.createRequire)(node_path_1.default.join(root, 'package.json'));
|
|
48
|
+
const manifest = node_path_1.default.resolve(node_path_1.default.dirname(require.resolve('@expo-harmony/expo-modules-autolinking')), '../package.json');
|
|
49
|
+
const bin = node_path_1.default.resolve(node_path_1.default.dirname(manifest), require(manifest).bin['expo-harmony-autolinking']);
|
|
50
|
+
run(nodeExecutable(), [bin, 'link', '--project-root', root, '--harmony-project-path', harmony, '--build-type', mode], root);
|
|
51
|
+
const { ohpm } = (0, toolchain_1.resolveHarmonyToolchain)();
|
|
52
|
+
run(ohpm.command, [...ohpm.args, 'install', '--all'], harmony);
|
|
53
|
+
}
|
|
54
|
+
publishHarmonyNativeRuntime(root, mode);
|
|
55
|
+
const { fingerprint } = (0, native_inputs_1.fingerprintHarmonyNativeInputsSync)({
|
|
56
|
+
projectRoot: root,
|
|
57
|
+
manifest: node_path_1.default.join(harmony, 'oh-package.json5'),
|
|
58
|
+
lockfile: node_path_1.default.join(harmony, 'oh-package-lock.json5'),
|
|
59
|
+
});
|
|
60
|
+
const file = node_path_1.default.join(harmony, '.hvigor/expo-harmony/native-inputs.cmake');
|
|
61
|
+
const content = `# Generated native dependency fingerprint.\nadd_compile_definitions(EXPO_HARMONY_NATIVE_INPUTS_SHA256_${fingerprint}=1)\n`;
|
|
62
|
+
if (node_fs_1.default.existsSync(file) && node_fs_1.default.readFileSync(file, 'utf8') === content)
|
|
63
|
+
return;
|
|
64
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(file), { recursive: true });
|
|
65
|
+
const temp = `${file}.${node_crypto_1.default.randomUUID()}.tmp`;
|
|
66
|
+
try {
|
|
67
|
+
node_fs_1.default.writeFileSync(temp, content);
|
|
68
|
+
node_fs_1.default.renameSync(temp, file);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
node_fs_1.default.rmSync(temp, { force: true });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function bundleHarmonyNativeBuild(root) {
|
|
75
|
+
if (process.env.EXPO_HARMONY_BUNDLE_PREBUILT === '1')
|
|
76
|
+
return;
|
|
77
|
+
const require = (0, node_module_1.createRequire)(node_path_1.default.join(root, 'package.json'));
|
|
78
|
+
run(nodeExecutable(), [require.resolve('@expo-harmony/cli/bin/expo-harmony'), 'export:embed', root], root);
|
|
79
|
+
}
|
|
80
|
+
function publishHarmonyNativeRuntime(root, mode) {
|
|
81
|
+
const require = (0, node_module_1.createRequire)(node_path_1.default.join(root, 'package.json'));
|
|
82
|
+
run(nodeExecutable(), [require.resolve('@expo-harmony/cli/bin/expo-harmony'), 'runtime', root, '--publish', '--variant', mode], root);
|
|
83
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { HarmonyBuildPlan } from './types';
|
|
2
|
+
import type { HarmonyToolchain } from './toolchain';
|
|
3
|
+
export declare function installHarmonyDependenciesAsync(plan: Pick<HarmonyBuildPlan, 'harmonyRoot'>, tools: HarmonyToolchain, options?: {
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.installHarmonyDependenciesAsync = installHarmonyDependenciesAsync;
|
|
4
|
+
const process_1 = require("../process");
|
|
5
|
+
async function installHarmonyDependenciesAsync(plan, tools, options = {}) {
|
|
6
|
+
await (0, process_1.runCheckedAsync)(tools.ohpm.command, [...tools.ohpm.args, 'install', '--all'], {
|
|
7
|
+
code: 'ERR_HARMONY_OHPM_FAILED',
|
|
8
|
+
cwd: plan.harmonyRoot,
|
|
9
|
+
message: 'OHPM install',
|
|
10
|
+
operation: 'ohpm-install',
|
|
11
|
+
timeoutMs: options.timeoutMs || 5 * 60_000,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Log } from '../log';
|
|
2
|
+
import type { HarmonyBuildPlan } from './types';
|
|
3
|
+
interface PrepareProjectOptions {
|
|
4
|
+
io?: Log;
|
|
5
|
+
requireDeviceTools?: boolean;
|
|
6
|
+
check?: boolean;
|
|
7
|
+
sync: boolean;
|
|
8
|
+
variant: 'debug' | 'release';
|
|
9
|
+
}
|
|
10
|
+
declare function prepareNativeProjectAsync(root: string, options: PrepareProjectOptions, steps: Record<string, number>): Promise<HarmonyBuildPlan>;
|
|
11
|
+
export { prepareNativeProjectAsync };
|
|
@@ -0,0 +1,68 @@
|
|
|
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.prepareNativeProjectAsync = prepareNativeProjectAsync;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const expo_modules_autolinking_1 = require("@expo-harmony/expo-modules-autolinking");
|
|
9
|
+
const doctor_1 = require("../doctor/doctor");
|
|
10
|
+
const errors_1 = require("../errors");
|
|
11
|
+
const log_1 = require("../log");
|
|
12
|
+
const profile_1 = require("../profile");
|
|
13
|
+
const check_1 = require("../prebuild/check");
|
|
14
|
+
const prebuild_1 = require("../prebuild/prebuild");
|
|
15
|
+
const toolchain_1 = require("./toolchain");
|
|
16
|
+
const project_1 = require("./project");
|
|
17
|
+
async function prepareNativeProjectAsync(root, options, steps) {
|
|
18
|
+
const plan = await (0, profile_1.timedAsync)(steps, 'buildPlan', () => (0, project_1.resolveHarmonyBuildPlanIfPresentAsync)(root, {
|
|
19
|
+
buildMode: options.variant,
|
|
20
|
+
}));
|
|
21
|
+
const exists = Boolean(plan && node_fs_1.default.existsSync(plan.harmonyRoot));
|
|
22
|
+
if (plan?.workflow === 'bare' && options.sync) {
|
|
23
|
+
throw new errors_1.HarmonyCliError('ERR_HARMONY_BARE_SYNC', '--sync regenerates CNG projects and cannot be used with a manually maintained bare project.', { operation: 'build' });
|
|
24
|
+
}
|
|
25
|
+
(0, log_1.progress)(options, 'Checking the Harmony project');
|
|
26
|
+
const doctor = await (0, profile_1.timedAsync)(steps, 'doctor', () => (0, doctor_1.doctorAsync)(root, {
|
|
27
|
+
requireBuildTools: true,
|
|
28
|
+
requireDeviceTools: options.requireDeviceTools,
|
|
29
|
+
validateGeneratedProject: exists,
|
|
30
|
+
validateModules: false,
|
|
31
|
+
}));
|
|
32
|
+
if (!doctor.ok) {
|
|
33
|
+
const checks = doctor.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: ${checks.join(', ') || 'unknown'}.`, { operation: 'doctor' });
|
|
35
|
+
}
|
|
36
|
+
if (plan?.workflow === 'bare') {
|
|
37
|
+
(0, log_1.progress)(options, 'Autolinking the bare Harmony project');
|
|
38
|
+
await (0, profile_1.timedAsync)(steps, 'autolinking', () => (0, expo_modules_autolinking_1.linkModulesAsync)({
|
|
39
|
+
projectRoot: root,
|
|
40
|
+
harmonyProjectPath: plan.harmonyRoot,
|
|
41
|
+
buildType: options.variant,
|
|
42
|
+
env: (0, toolchain_1.createHarmonyToolchainEnv)(),
|
|
43
|
+
}));
|
|
44
|
+
steps.prebuild = 0;
|
|
45
|
+
steps.cngCheck = 0;
|
|
46
|
+
return plan;
|
|
47
|
+
}
|
|
48
|
+
if (!exists || options.sync) {
|
|
49
|
+
(0, log_1.progress)(options, exists
|
|
50
|
+
? 'Synchronizing the generated Harmony project'
|
|
51
|
+
: 'Generating the missing Harmony project');
|
|
52
|
+
await (0, profile_1.timedAsync)(steps, 'prebuild', () => (0, prebuild_1.prebuildParsedAsync)(root, [], { buildType: options.variant }));
|
|
53
|
+
steps.cngCheck = 0;
|
|
54
|
+
return (0, profile_1.timedAsync)(steps, 'buildPlan', () => (0, project_1.resolveHarmonyBuildPlanAsync)(root, { buildMode: options.variant }));
|
|
55
|
+
}
|
|
56
|
+
steps.prebuild = 0;
|
|
57
|
+
if (options.check === false) {
|
|
58
|
+
steps.cngCheck = 0;
|
|
59
|
+
return plan;
|
|
60
|
+
}
|
|
61
|
+
(0, log_1.progress)(options, 'Checking CNG ownership and drift');
|
|
62
|
+
const check = await (0, profile_1.timedAsync)(steps, 'cngCheck', () => (0, check_1.checkAsync)(root, { buildType: options.variant }));
|
|
63
|
+
if (!check.clean) {
|
|
64
|
+
const summary = check.changes.slice(0, 8).map(change => `${change.type}:${change.path}`).join(', ');
|
|
65
|
+
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' });
|
|
66
|
+
}
|
|
67
|
+
return plan;
|
|
68
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HarmonyBuildPlan } from './types';
|
|
2
|
+
declare function resolveHarmonyBuildPlanIfPresentAsync(root: string, options?: {
|
|
3
|
+
buildMode?: 'debug' | 'release';
|
|
4
|
+
}): Promise<HarmonyBuildPlan | null>;
|
|
5
|
+
declare function resolveHarmonyBuildPlanAsync(root: string, options?: {
|
|
6
|
+
buildMode?: 'debug' | 'release';
|
|
7
|
+
}): Promise<HarmonyBuildPlan>;
|
|
8
|
+
export { resolveHarmonyBuildPlanAsync, resolveHarmonyBuildPlanIfPresentAsync };
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resolveHarmonyBuildPlanAsync = resolveHarmonyBuildPlanAsync;
|
|
4
|
+
exports.resolveHarmonyBuildPlanIfPresentAsync = resolveHarmonyBuildPlanIfPresentAsync;
|
|
5
|
+
const internal_1 = require("@expo-harmony/prebuild-config/internal");
|
|
6
|
+
const errors_1 = require("../errors");
|
|
7
|
+
const bare_1 = require("./bare");
|
|
8
|
+
function createHarmonyBuildPlan(root, build, mode) {
|
|
9
|
+
const resolve = relative => (0, internal_1.resolveHarmonyBuildPath)(root, relative);
|
|
10
|
+
const variant = build.variants[mode];
|
|
11
|
+
return {
|
|
12
|
+
workflow: 'cng',
|
|
13
|
+
abilityName: build.identity.abilityName,
|
|
14
|
+
buildMode: mode,
|
|
15
|
+
bundleName: build.identity.bundleName,
|
|
16
|
+
expectedHap: resolve(variant.expectedHap),
|
|
17
|
+
exportPaths: Object.fromEntries(Object.entries(build.export).map(([name, relative]) => [name, resolve(relative)])),
|
|
18
|
+
harmonyRoot: resolve(build.harmonyRoot),
|
|
19
|
+
hvigorArgs: [...variant.hvigorArgs],
|
|
20
|
+
moduleName: build.identity.moduleName,
|
|
21
|
+
moduleRoot: resolve(build.moduleRoot),
|
|
22
|
+
nativeCache: {
|
|
23
|
+
invalidationRoots: build.nativeCache.invalidationRoots.map(resolve),
|
|
24
|
+
stateFile: resolve(build.nativeCache.stateFile),
|
|
25
|
+
},
|
|
26
|
+
nativeInputs: {
|
|
27
|
+
lockfile: resolve(build.nativeInputs.lockfile),
|
|
28
|
+
manifest: resolve(build.nativeInputs.manifest),
|
|
29
|
+
},
|
|
30
|
+
productName: build.identity.productName,
|
|
31
|
+
projectFiles: Object.fromEntries(Object.entries(build.projectFiles).map(([name, relative]) => [name, resolve(relative)])),
|
|
32
|
+
targetName: build.identity.targetName,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async function resolveHarmonyBuildPlanIfPresentAsync(root, options = {}) {
|
|
36
|
+
const mode = options.buildMode || 'debug';
|
|
37
|
+
if (!['debug', 'release'].includes(mode)) {
|
|
38
|
+
throw new errors_1.HarmonyCliError('ERR_HARMONY_CONFIG_INVALID', `Harmony buildMode must be debug or release, received: ${mode}`, { operation: 'resolve-build' });
|
|
39
|
+
}
|
|
40
|
+
let manifest;
|
|
41
|
+
try {
|
|
42
|
+
manifest = await (0, internal_1.readManifestIfPresentAsync)(root);
|
|
43
|
+
}
|
|
44
|
+
catch (cause) {
|
|
45
|
+
throw new errors_1.HarmonyCliError(cause.code || 'ERR_HARMONY_TEMPLATE_INVALID', `Cannot read the generated Harmony build descriptor: ${cause.message}`, { cause, operation: 'resolve-build' });
|
|
46
|
+
}
|
|
47
|
+
if (!manifest) {
|
|
48
|
+
return (0, bare_1.isBareHarmonyProject)(root) ? (0, bare_1.resolveBareHarmonyBuildPlan)(root, mode) : null;
|
|
49
|
+
}
|
|
50
|
+
return createHarmonyBuildPlan(root, manifest.build, mode);
|
|
51
|
+
}
|
|
52
|
+
async function resolveHarmonyBuildPlanAsync(root, options = {}) {
|
|
53
|
+
const plan = await resolveHarmonyBuildPlanIfPresentAsync(root, options);
|
|
54
|
+
if (!plan) {
|
|
55
|
+
throw new errors_1.HarmonyCliError('ERR_HARMONY_MANIFEST_DRIFT', 'Cannot read the generated Harmony build descriptor because the CNG manifest is missing.', { operation: 'resolve-build' });
|
|
56
|
+
}
|
|
57
|
+
return plan;
|
|
58
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface HarmonyTool {
|
|
2
|
+
args: string[];
|
|
3
|
+
command: string;
|
|
4
|
+
source: 'deveco' | 'override' | 'path';
|
|
5
|
+
}
|
|
6
|
+
export interface HarmonyToolchain {
|
|
7
|
+
hdc: HarmonyTool;
|
|
8
|
+
hvigor: HarmonyTool;
|
|
9
|
+
ohpm: HarmonyTool;
|
|
10
|
+
sdkHome: string | null;
|
|
11
|
+
toolsRoot: string | null;
|
|
12
|
+
}
|
|
13
|
+
declare function resolveHarmonyToolchain(): HarmonyToolchain;
|
|
14
|
+
declare function createHarmonyToolchainEnv(toolchain?: HarmonyToolchain): NodeJS.ProcessEnv;
|
|
15
|
+
declare function resolveHarmonyEmulator(toolchain: HarmonyToolchain): HarmonyTool;
|
|
16
|
+
export { createHarmonyToolchainEnv, resolveHarmonyEmulator, resolveHarmonyToolchain };
|
|
@@ -0,0 +1,172 @@
|
|
|
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.createHarmonyToolchainEnv = createHarmonyToolchainEnv;
|
|
7
|
+
exports.resolveHarmonyEmulator = resolveHarmonyEmulator;
|
|
8
|
+
exports.resolveHarmonyToolchain = resolveHarmonyToolchain;
|
|
9
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const tool_command_1 = require("@expo-harmony/expo-modules-autolinking/tool-command");
|
|
12
|
+
function existingFile(candidates) {
|
|
13
|
+
return candidates.find(candidate => node_fs_1.default.existsSync(candidate)) || null;
|
|
14
|
+
}
|
|
15
|
+
const RequiredSdkComponents = Object.freeze([
|
|
16
|
+
'default/sdk-pkg.json',
|
|
17
|
+
'default/hms/ets/uni-package.json',
|
|
18
|
+
'default/hms/native/uni-package.json',
|
|
19
|
+
'default/hms/toolchains/uni-package.json',
|
|
20
|
+
'default/openharmony/ets/oh-uni-package.json',
|
|
21
|
+
'default/openharmony/native/oh-uni-package.json',
|
|
22
|
+
'default/openharmony/toolchains/oh-uni-package.json',
|
|
23
|
+
]);
|
|
24
|
+
function sdkRootsNear(seed) {
|
|
25
|
+
const roots = [];
|
|
26
|
+
let cursor = node_path_1.default.resolve(seed);
|
|
27
|
+
for (let depth = 0; depth < 6; depth += 1) {
|
|
28
|
+
const name = node_path_1.default.basename(cursor).toLowerCase();
|
|
29
|
+
if (name === 'default' && node_path_1.default.basename(node_path_1.default.dirname(cursor)).toLowerCase() === 'sdk') {
|
|
30
|
+
roots.push(node_path_1.default.dirname(cursor));
|
|
31
|
+
}
|
|
32
|
+
if (name === 'sdk')
|
|
33
|
+
roots.push(cursor);
|
|
34
|
+
roots.push(node_path_1.default.join(cursor, 'sdk'));
|
|
35
|
+
const parent = node_path_1.default.dirname(cursor);
|
|
36
|
+
if (parent === cursor)
|
|
37
|
+
break;
|
|
38
|
+
cursor = parent;
|
|
39
|
+
}
|
|
40
|
+
return roots;
|
|
41
|
+
}
|
|
42
|
+
function resolveHarmonySdkRoot(env, platform) {
|
|
43
|
+
const seeds = [
|
|
44
|
+
env.DEVECO_SDK_HOME,
|
|
45
|
+
env.HARMONY_HOME,
|
|
46
|
+
env.OHOS_SDK_HOME,
|
|
47
|
+
env.HARMONY_HVIGORW,
|
|
48
|
+
env.HARMONY_OHPM,
|
|
49
|
+
env.HARMONY_NODE,
|
|
50
|
+
...(env.PATH || '').split(node_path_1.default.delimiter).filter(Boolean),
|
|
51
|
+
...(platform === 'darwin' ? ['/Applications/DevEco-Studio.app/Contents'] : []),
|
|
52
|
+
].filter(Boolean);
|
|
53
|
+
const candidates = [...new Set(seeds.flatMap(sdkRootsNear))];
|
|
54
|
+
return candidates.find(root => RequiredSdkComponents.every(relative => node_fs_1.default.existsSync(node_path_1.default.join(root, ...relative.split('/'))))) || null;
|
|
55
|
+
}
|
|
56
|
+
function devEcoInstallRoots(sdkHome) {
|
|
57
|
+
const ancestors = [sdkHome, node_path_1.default.dirname(sdkHome), node_path_1.default.dirname(node_path_1.default.dirname(sdkHome))];
|
|
58
|
+
const sdkDirectory = ancestors.find(candidate => node_path_1.default.basename(candidate).toLowerCase() === 'sdk');
|
|
59
|
+
const roots = [
|
|
60
|
+
sdkDirectory && node_path_1.default.dirname(sdkDirectory),
|
|
61
|
+
node_path_1.default.dirname(sdkHome),
|
|
62
|
+
node_path_1.default.dirname(node_path_1.default.dirname(sdkHome)),
|
|
63
|
+
].filter(Boolean);
|
|
64
|
+
return [...new Set(roots)];
|
|
65
|
+
}
|
|
66
|
+
function devEcoLayouts(sdkHome) {
|
|
67
|
+
return devEcoInstallRoots(sdkHome).flatMap(root => [
|
|
68
|
+
{
|
|
69
|
+
nodeRoot: node_path_1.default.join(root, 'tools', 'node'),
|
|
70
|
+
toolsRoot: node_path_1.default.join(root, 'tools'),
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
nodeRoot: node_path_1.default.join(root, 'tool', 'node'),
|
|
74
|
+
toolsRoot: root,
|
|
75
|
+
},
|
|
76
|
+
]);
|
|
77
|
+
}
|
|
78
|
+
function devEcoNode(layout, platform, env) {
|
|
79
|
+
if (env.HARMONY_NODE)
|
|
80
|
+
return { command: env.HARMONY_NODE, source: 'override' };
|
|
81
|
+
const executable = platform === 'win32' ? 'node.exe' : 'node';
|
|
82
|
+
const command = existingFile([
|
|
83
|
+
node_path_1.default.join(layout.nodeRoot, 'bin', executable),
|
|
84
|
+
node_path_1.default.join(layout.nodeRoot, executable),
|
|
85
|
+
]);
|
|
86
|
+
return command ? { command, source: 'deveco' } : null;
|
|
87
|
+
}
|
|
88
|
+
function resolveHarmonyToolchain() {
|
|
89
|
+
const env = process.env;
|
|
90
|
+
const platform = process.platform;
|
|
91
|
+
// Hvigor needs the complete SDK root containing default/, not default/ itself.
|
|
92
|
+
const sdkHome = resolveHarmonySdkRoot(env, platform);
|
|
93
|
+
const layouts = sdkHome ? devEcoLayouts(sdkHome) : [];
|
|
94
|
+
let ohpm;
|
|
95
|
+
if (env.HARMONY_OHPM) {
|
|
96
|
+
ohpm = { ...(0, tool_command_1.resolveHarmonyCommand)('ohpm', [], env), source: 'override' };
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
const entry = layouts.map(layout => ({
|
|
100
|
+
node: devEcoNode(layout, platform, { ...env, HARMONY_NODE: env.HARMONY_OHPM_NODE || env.HARMONY_NODE }),
|
|
101
|
+
script: node_path_1.default.join(layout.toolsRoot, 'ohpm', 'bin', 'pm-cli.js'),
|
|
102
|
+
})).find(candidate => candidate.node && node_fs_1.default.existsSync(candidate.script));
|
|
103
|
+
const command = existingFile(layouts.map(layout => node_path_1.default.join(layout.toolsRoot, 'ohpm', 'bin', platform === 'win32' ? 'ohpm.bat' : 'ohpm')));
|
|
104
|
+
ohpm = entry
|
|
105
|
+
? { args: [entry.script], command: entry.node.command, source: 'deveco' }
|
|
106
|
+
: command
|
|
107
|
+
? { args: [], command, source: 'deveco' }
|
|
108
|
+
: { args: [], command: platform === 'win32' ? 'ohpm.bat' : 'ohpm', source: 'path' };
|
|
109
|
+
}
|
|
110
|
+
let hvigor;
|
|
111
|
+
if (env.HARMONY_HVIGORW) {
|
|
112
|
+
hvigor = { ...(0, tool_command_1.resolveHarmonyCommand)('hvigorw', [], env), source: 'override' };
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
const entry = layouts.map(layout => ({
|
|
116
|
+
node: devEcoNode(layout, platform, { ...env, HARMONY_NODE: env.HARMONY_HVIGOR_NODE || env.HARMONY_NODE }),
|
|
117
|
+
script: node_path_1.default.join(layout.toolsRoot, 'hvigor', 'bin', 'hvigorw.js'),
|
|
118
|
+
})).find(candidate => candidate.node && node_fs_1.default.existsSync(candidate.script));
|
|
119
|
+
hvigor = entry
|
|
120
|
+
? { args: [entry.script], command: entry.node.command, source: 'deveco' }
|
|
121
|
+
: { args: [], command: platform === 'win32' ? 'hvigorw.bat' : 'hvigorw', source: 'path' };
|
|
122
|
+
}
|
|
123
|
+
const toolsRoot = layouts.find(layout => (hvigor.args[0]?.startsWith(`${layout.toolsRoot}${node_path_1.default.sep}`)
|
|
124
|
+
|| ohpm.args[0]?.startsWith(`${layout.toolsRoot}${node_path_1.default.sep}`)
|
|
125
|
+
|| ohpm.command.startsWith(`${layout.toolsRoot}${node_path_1.default.sep}`)))?.toolsRoot || null;
|
|
126
|
+
let hdc;
|
|
127
|
+
if (env.HARMONY_HDC) {
|
|
128
|
+
hdc = { args: [], command: env.HARMONY_HDC, source: 'override' };
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
const executable = platform === 'win32' ? 'hdc.exe' : 'hdc';
|
|
132
|
+
const sdkHdc = sdkHome && existingFile([
|
|
133
|
+
node_path_1.default.join(sdkHome, 'default', 'openharmony', 'toolchains', executable),
|
|
134
|
+
node_path_1.default.join(sdkHome, 'default', 'hms', 'toolchains', executable),
|
|
135
|
+
]);
|
|
136
|
+
hdc = sdkHdc
|
|
137
|
+
? { args: [], command: sdkHdc, source: 'deveco' }
|
|
138
|
+
: { args: [], command: executable, source: 'path' };
|
|
139
|
+
}
|
|
140
|
+
return { hdc, hvigor, ohpm, sdkHome, toolsRoot };
|
|
141
|
+
}
|
|
142
|
+
function createHarmonyToolchainEnv(toolchain = resolveHarmonyToolchain()) {
|
|
143
|
+
return {
|
|
144
|
+
...process.env,
|
|
145
|
+
HARMONY_OHPM: toolchain.ohpm.args[0] || toolchain.ohpm.command,
|
|
146
|
+
HARMONY_OHPM_NODE: toolchain.ohpm.args.length > 0 ? toolchain.ohpm.command : undefined,
|
|
147
|
+
// Script-based tools must retain both their script and Node executable.
|
|
148
|
+
HARMONY_HVIGORW: toolchain.hvigor.args[0] || toolchain.hvigor.command,
|
|
149
|
+
HARMONY_HVIGOR_NODE: toolchain.hvigor.args.length > 0 ? toolchain.hvigor.command : undefined,
|
|
150
|
+
...(toolchain.hvigor.args.length > 0
|
|
151
|
+
? { HARMONY_NODE: toolchain.hvigor.command }
|
|
152
|
+
: toolchain.ohpm.args.length > 0 ? { HARMONY_NODE: toolchain.ohpm.command } : {}),
|
|
153
|
+
...(toolchain.sdkHome && !process.env.DEVECO_SDK_HOME
|
|
154
|
+
? { DEVECO_SDK_HOME: toolchain.sdkHome }
|
|
155
|
+
: {}),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function resolveHarmonyEmulator(toolchain) {
|
|
159
|
+
if (process.env.HARMONY_EMULATOR) {
|
|
160
|
+
return { args: [], command: process.env.HARMONY_EMULATOR, source: 'override' };
|
|
161
|
+
}
|
|
162
|
+
const executable = process.platform === 'win32' ? 'Emulator.exe' : 'Emulator';
|
|
163
|
+
const roots = [
|
|
164
|
+
toolchain.toolsRoot,
|
|
165
|
+
...(toolchain.sdkHome ? devEcoLayouts(toolchain.sdkHome).map(layout => layout.toolsRoot) : []),
|
|
166
|
+
...(process.platform === 'darwin' ? ['/Applications/DevEco-Studio.app/Contents/tools'] : []),
|
|
167
|
+
].filter(Boolean);
|
|
168
|
+
const command = existingFile(roots.map(root => node_path_1.default.join(root, 'emulator', executable)));
|
|
169
|
+
return command
|
|
170
|
+
? { args: [], command, source: 'deveco' }
|
|
171
|
+
: { args: [], command: executable, source: 'path' };
|
|
172
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type HarmonyBuildMode = 'debug' | 'release';
|
|
2
|
+
interface NativeBuildPlan {
|
|
3
|
+
abilityName: string;
|
|
4
|
+
buildMode: HarmonyBuildMode;
|
|
5
|
+
bundleName: string;
|
|
6
|
+
expectedHap: string;
|
|
7
|
+
exportPaths: {
|
|
8
|
+
bundle: string;
|
|
9
|
+
manifest: string;
|
|
10
|
+
metadataRoot: string;
|
|
11
|
+
rawfileRoot: string;
|
|
12
|
+
sourceMap: string;
|
|
13
|
+
};
|
|
14
|
+
harmonyRoot: string;
|
|
15
|
+
hvigorArgs: string[];
|
|
16
|
+
moduleName: string;
|
|
17
|
+
moduleRoot: string;
|
|
18
|
+
nativeCache: {
|
|
19
|
+
invalidationRoots: string[];
|
|
20
|
+
stateFile: string;
|
|
21
|
+
};
|
|
22
|
+
nativeInputs: {
|
|
23
|
+
lockfile: string;
|
|
24
|
+
manifest: string;
|
|
25
|
+
};
|
|
26
|
+
projectFiles: {
|
|
27
|
+
hvigorConfig: string;
|
|
28
|
+
moduleHvigor: string;
|
|
29
|
+
moduleJson: string;
|
|
30
|
+
projectBuildProfile: string;
|
|
31
|
+
rootHvigor: string;
|
|
32
|
+
};
|
|
33
|
+
productName: string;
|
|
34
|
+
targetName: string;
|
|
35
|
+
}
|
|
36
|
+
export interface BareHarmonyBuildPlan extends NativeBuildPlan {
|
|
37
|
+
workflow: 'bare';
|
|
38
|
+
}
|
|
39
|
+
export interface CngHarmonyBuildPlan extends NativeBuildPlan {
|
|
40
|
+
workflow: 'cng';
|
|
41
|
+
projectFiles: NativeBuildPlan['projectFiles'] & {
|
|
42
|
+
nativeInputsStamp: string;
|
|
43
|
+
templateMarker: string;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export type HarmonyBuildPlan = BareHarmonyBuildPlan | CngHarmonyBuildPlan;
|
|
47
|
+
export {};
|
package/build/path.d.ts
ADDED
package/build/path.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
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.assertSafeRelative = assertSafeRelative;
|
|
7
|
+
exports.isInside = isInside;
|
|
8
|
+
exports.toPosixPath = toPosixPath;
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
function isInside(root, target) {
|
|
11
|
+
const relative = node_path_1.default.relative(root, target);
|
|
12
|
+
return relative === ''
|
|
13
|
+
|| (relative !== '..' && !relative.startsWith(`..${node_path_1.default.sep}`) && !node_path_1.default.isAbsolute(relative));
|
|
14
|
+
}
|
|
15
|
+
function toPosixPath(value) {
|
|
16
|
+
return value.split(node_path_1.default.sep).join('/');
|
|
17
|
+
}
|
|
18
|
+
function assertSafeRelative(relative, label) {
|
|
19
|
+
const segments = typeof relative === 'string' ? relative.split('/') : [];
|
|
20
|
+
const native = segments.join(node_path_1.default.sep);
|
|
21
|
+
if (!relative || relative.includes('\\') || relative.includes('\0')
|
|
22
|
+
|| segments.some(segment => !segment || segment === '.' || segment === '..')
|
|
23
|
+
|| node_path_1.default.isAbsolute(native)) {
|
|
24
|
+
throw new Error(`${label} contains an unsafe path.`);
|
|
25
|
+
}
|
|
26
|
+
return native;
|
|
27
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type { Change as CheckChange } from '@expo-harmony/prebuild-config/internal';
|
|
2
|
+
interface CheckOptions {
|
|
3
|
+
buildType?: 'debug' | 'release';
|
|
4
|
+
}
|
|
5
|
+
declare function withGeneratedProjectAsync<T>(project: string, options: CheckOptions & {
|
|
6
|
+
clean?: boolean;
|
|
7
|
+
skipPatches?: boolean;
|
|
8
|
+
}, action: (expected: string, checksum: string) => Promise<T>): Promise<T>;
|
|
9
|
+
declare function checkAsync(project: any, options?: CheckOptions): Promise<import("@expo-harmony/prebuild-config/internal").Result>;
|
|
10
|
+
export { checkAsync, withGeneratedProjectAsync };
|