@revopush/code-push-cli 0.0.5 → 0.0.7
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/bin/script/command-executor.js +44 -32
- package/bin/script/react-native-utils.js +188 -16
- package/package.json +2 -1
- package/script/command-executor.ts +69 -46
- package/script/react-native-utils.ts +206 -20
- package/test.json +5963 -0
- package/test2.json +5844 -0
|
@@ -3,35 +3,34 @@
|
|
|
3
3
|
// Licensed under the MIT License.
|
|
4
4
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
5
|
exports.runReactNativeBundleCommand = exports.releaseReact = exports.release = exports.execute = exports.deploymentList = exports.createEmptyTempReleaseFolder = exports.confirm = exports.execSync = exports.spawn = exports.sdk = exports.log = void 0;
|
|
6
|
-
const AccountManager = require("./management-sdk");
|
|
7
6
|
const childProcess = require("child_process");
|
|
8
7
|
const debug_1 = require("./commands/debug");
|
|
9
8
|
const fs = require("fs");
|
|
10
9
|
const chalk = require("chalk");
|
|
11
|
-
const g2js = require("gradle-to-js/lib/parser");
|
|
12
10
|
const moment = require("moment");
|
|
13
|
-
const opener = require("opener");
|
|
14
11
|
const os = require("os");
|
|
15
12
|
const path = require("path");
|
|
16
|
-
const plist = require("plist");
|
|
17
|
-
const progress = require("progress");
|
|
18
|
-
const prompt = require("prompt");
|
|
19
13
|
const Q = require("q");
|
|
20
|
-
const rimraf = require("rimraf");
|
|
21
14
|
const semver = require("semver");
|
|
22
|
-
const Table = require("cli-table");
|
|
23
|
-
const which = require("which");
|
|
24
|
-
const wordwrap = require("wordwrap");
|
|
25
15
|
const cli = require("../script/types/cli");
|
|
26
16
|
const sign_1 = require("./sign");
|
|
27
|
-
const xcode = require("xcode");
|
|
28
17
|
const react_native_utils_1 = require("./react-native-utils");
|
|
29
18
|
const file_utils_1 = require("./utils/file-utils");
|
|
19
|
+
const AccountManager = require("./management-sdk");
|
|
20
|
+
const wordwrap = require("wordwrap");
|
|
21
|
+
var Promise = Q.Promise;
|
|
22
|
+
const g2js = require("gradle-to-js/lib/parser");
|
|
23
|
+
const opener = require("opener");
|
|
24
|
+
const plist = require("plist");
|
|
25
|
+
const progress = require("progress");
|
|
26
|
+
const prompt = require("prompt");
|
|
27
|
+
const rimraf = require("rimraf");
|
|
28
|
+
const Table = require("cli-table");
|
|
29
|
+
const xcode = require("xcode");
|
|
30
30
|
const configFilePath = path.join(process.env.LOCALAPPDATA || process.env.HOME, ".revopush.config");
|
|
31
31
|
const emailValidator = require("email-validator");
|
|
32
32
|
const packageJson = require("../../package.json");
|
|
33
33
|
const parseXml = Q.denodeify(require("xml2js").parseString);
|
|
34
|
-
var Promise = Q.Promise;
|
|
35
34
|
const properties = require("properties");
|
|
36
35
|
const CLI_HEADERS = {
|
|
37
36
|
"X-CodePush-CLI-Version": packageJson.version,
|
|
@@ -237,12 +236,11 @@ function deploymentHistoryClear(command) {
|
|
|
237
236
|
const deploymentList = (command, showPackage = true) => {
|
|
238
237
|
throwForInvalidOutputFormat(command.format);
|
|
239
238
|
let deployments;
|
|
240
|
-
const DEPLOYMENTS_MAX_LENGTH = 10; // do not take metrics if number of deployment higher than this
|
|
241
239
|
return exports.sdk
|
|
242
240
|
.getDeployments(command.appName)
|
|
243
241
|
.then((retrievedDeployments) => {
|
|
244
242
|
deployments = retrievedDeployments;
|
|
245
|
-
if (showPackage
|
|
243
|
+
if (showPackage) {
|
|
246
244
|
const metricsPromises = deployments.map((deployment) => {
|
|
247
245
|
if (deployment.package) {
|
|
248
246
|
return exports.sdk.getDeploymentMetrics(command.appName, deployment.name).then((metrics) => {
|
|
@@ -1020,13 +1018,14 @@ const releaseReact = (command) => {
|
|
|
1020
1018
|
let bundleName = command.bundleName;
|
|
1021
1019
|
let entryFile = command.entryFile;
|
|
1022
1020
|
const outputFolder = command.outputDir || path.join(os.tmpdir(), "CodePush");
|
|
1021
|
+
const sourcemapOutputFolder = command.sourcemapOutput || path.join(os.tmpdir(), "CodePushSourceMap");
|
|
1023
1022
|
const platform = (command.platform = command.platform.toLowerCase());
|
|
1024
1023
|
const releaseCommand = command;
|
|
1025
1024
|
// Check for app and deployment exist before releasing an update.
|
|
1026
1025
|
// This validation helps to save about 1 minute or more in case user has typed wrong app or deployment name.
|
|
1027
1026
|
return (exports.sdk
|
|
1028
1027
|
.getDeployment(command.appName, command.deploymentName)
|
|
1029
|
-
.then(() => {
|
|
1028
|
+
.then(async () => {
|
|
1030
1029
|
releaseCommand.package = outputFolder;
|
|
1031
1030
|
switch (platform) {
|
|
1032
1031
|
case "android":
|
|
@@ -1070,8 +1069,9 @@ const releaseReact = (command) => {
|
|
|
1070
1069
|
const appVersionPromise = command.appStoreVersion
|
|
1071
1070
|
? Q(command.appStoreVersion)
|
|
1072
1071
|
: getReactNativeProjectAppVersion(command, projectName);
|
|
1073
|
-
if (
|
|
1074
|
-
|
|
1072
|
+
if (!sourcemapOutputFolder.endsWith(".map") && !command.sourcemapOutput) {
|
|
1073
|
+
// create tmp dir only if no dir was given by user. User must crete a directory if --sourcemapOutput is passes
|
|
1074
|
+
await (0, exports.createEmptyTempReleaseFolder)(sourcemapOutputFolder);
|
|
1075
1075
|
}
|
|
1076
1076
|
return appVersionPromise;
|
|
1077
1077
|
})
|
|
@@ -1083,14 +1083,14 @@ const releaseReact = (command) => {
|
|
|
1083
1083
|
// This is needed to clear the react native bundler cache:
|
|
1084
1084
|
// https://github.com/facebook/react-native/issues/4289
|
|
1085
1085
|
.then(() => deleteFolder(`${os.tmpdir()}/react-*`))
|
|
1086
|
-
.then(() => (0, exports.runReactNativeBundleCommand)(bundleName, command.development || false, entryFile, outputFolder, platform, command.sourcemapOutput, command.extraBundlerOptions))
|
|
1087
1086
|
.then(async () => {
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1087
|
+
await (0, exports.runReactNativeBundleCommand)(command, bundleName, command.development || false, entryFile, outputFolder, sourcemapOutputFolder, platform, command.extraBundlerOptions);
|
|
1088
|
+
})
|
|
1089
|
+
.then(async () => {
|
|
1090
|
+
const isHermes = await (0, react_native_utils_1.isHermesEnabled)(command, platform);
|
|
1091
|
+
if (isHermes) {
|
|
1092
1092
|
(0, exports.log)(chalk.cyan("\nRunning hermes compiler...\n"));
|
|
1093
|
-
await (0, react_native_utils_1.runHermesEmitBinaryCommand)(bundleName, outputFolder,
|
|
1093
|
+
await (0, react_native_utils_1.runHermesEmitBinaryCommand)(command, bundleName, outputFolder, sourcemapOutputFolder, command.extraHermesFlags, command.gradleFile);
|
|
1094
1094
|
}
|
|
1095
1095
|
})
|
|
1096
1096
|
.then(async () => {
|
|
@@ -1106,13 +1106,15 @@ const releaseReact = (command) => {
|
|
|
1106
1106
|
(0, exports.log)(chalk.cyan("\nReleasing update contents to CodePush:\n"));
|
|
1107
1107
|
return (0, exports.release)(releaseCommand);
|
|
1108
1108
|
})
|
|
1109
|
-
.then(() => {
|
|
1109
|
+
.then(async () => {
|
|
1110
1110
|
if (!command.outputDir) {
|
|
1111
|
-
deleteFolder(outputFolder);
|
|
1111
|
+
await deleteFolder(outputFolder);
|
|
1112
|
+
}
|
|
1113
|
+
if (!command.sourcemapOutput) {
|
|
1114
|
+
await deleteFolder(sourcemapOutputFolder);
|
|
1112
1115
|
}
|
|
1113
1116
|
})
|
|
1114
|
-
.catch((err) => {
|
|
1115
|
-
deleteFolder(outputFolder);
|
|
1117
|
+
.catch(async (err) => {
|
|
1116
1118
|
throw err;
|
|
1117
1119
|
}));
|
|
1118
1120
|
};
|
|
@@ -1149,15 +1151,17 @@ function requestAccessKey() {
|
|
|
1149
1151
|
});
|
|
1150
1152
|
});
|
|
1151
1153
|
}
|
|
1152
|
-
const runReactNativeBundleCommand = (bundleName, development, entryFile, outputFolder,
|
|
1154
|
+
const runReactNativeBundleCommand = async (command, bundleName, development, entryFile, outputFolder, sourcemapOutputFolder, platform, extraBundlerOptions) => {
|
|
1153
1155
|
const reactNativeBundleArgs = [];
|
|
1154
1156
|
const envNodeArgs = process.env.CODE_PUSH_NODE_ARGS;
|
|
1155
1157
|
if (typeof envNodeArgs !== "undefined") {
|
|
1156
1158
|
Array.prototype.push.apply(reactNativeBundleArgs, envNodeArgs.trim().split(/\s+/));
|
|
1157
1159
|
}
|
|
1158
|
-
const
|
|
1160
|
+
const reactNativePackagePath = (0, react_native_utils_1.getReactNativePackagePath)();
|
|
1161
|
+
const oldCliPath = path.join(reactNativePackagePath, "local-cli", "cli.js");
|
|
1162
|
+
const cliPath = fs.existsSync(oldCliPath) ? oldCliPath : path.join(reactNativePackagePath, "cli.js");
|
|
1159
1163
|
Array.prototype.push.apply(reactNativeBundleArgs, [
|
|
1160
|
-
|
|
1164
|
+
cliPath,
|
|
1161
1165
|
"bundle",
|
|
1162
1166
|
"--assets-dest",
|
|
1163
1167
|
outputFolder,
|
|
@@ -1169,10 +1173,18 @@ const runReactNativeBundleCommand = (bundleName, development, entryFile, outputF
|
|
|
1169
1173
|
entryFile,
|
|
1170
1174
|
"--platform",
|
|
1171
1175
|
platform,
|
|
1176
|
+
"--reset-cache",
|
|
1172
1177
|
]);
|
|
1173
|
-
if (
|
|
1174
|
-
|
|
1178
|
+
if (sourcemapOutputFolder) {
|
|
1179
|
+
let bundleSourceMapOutput = sourcemapOutputFolder;
|
|
1180
|
+
if (!sourcemapOutputFolder.endsWith(".map")) {
|
|
1181
|
+
// user defined full path to source map. let's use that instead
|
|
1182
|
+
bundleSourceMapOutput = await (0, react_native_utils_1.getBundleSourceMapOutput)(command, bundleName, sourcemapOutputFolder);
|
|
1183
|
+
}
|
|
1184
|
+
reactNativeBundleArgs.push("--sourcemap-output", bundleSourceMapOutput);
|
|
1175
1185
|
}
|
|
1186
|
+
const minifyValue = await (0, react_native_utils_1.getMinifyParams)(command);
|
|
1187
|
+
Array.prototype.push.apply(reactNativeBundleArgs, minifyValue);
|
|
1176
1188
|
if (extraBundlerOptions.length > 0) {
|
|
1177
1189
|
reactNativeBundleArgs.push(...extraBundlerOptions);
|
|
1178
1190
|
}
|
|
@@ -1,18 +1,50 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getReactNativeVersion = exports.directoryExistsSync = exports.
|
|
3
|
+
exports.getReactNativeVersion = exports.directoryExistsSync = exports.getReactNativePackagePath = exports.isHermesEnabled = exports.getMinifyParams = exports.getXcodeDotEnvValue = exports.runHermesEmitBinaryCommand = exports.getBundleSourceMapOutput = exports.isValidVersion = void 0;
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const chalk = require("chalk");
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const childProcess = require("child_process");
|
|
8
8
|
const semver_1 = require("semver");
|
|
9
9
|
const file_utils_1 = require("./utils/file-utils");
|
|
10
|
+
const dotenv = require("dotenv");
|
|
10
11
|
const g2js = require("gradle-to-js/lib/parser");
|
|
11
12
|
function isValidVersion(version) {
|
|
12
13
|
return !!(0, semver_1.valid)(version) || /^\d+\.\d+$/.test(version);
|
|
13
14
|
}
|
|
14
15
|
exports.isValidVersion = isValidVersion;
|
|
15
|
-
async function
|
|
16
|
+
async function getBundleSourceMapOutput(command, bundleName, sourcemapOutputFolder) {
|
|
17
|
+
let bundleSourceMapOutput;
|
|
18
|
+
switch (command.platform) {
|
|
19
|
+
case "android": {
|
|
20
|
+
// see BundleHermesCTask -> resolvePackagerSourceMapFile
|
|
21
|
+
// for Hermes targeted bundles there are 2 source maps: "packager" (metro) and "compiler" (Hermes)
|
|
22
|
+
// Metro bundles use <bundleAssetName>.packager.map notation
|
|
23
|
+
const isHermes = await isHermesEnabled(command, command.platform);
|
|
24
|
+
if (isHermes) {
|
|
25
|
+
bundleSourceMapOutput = path.join(sourcemapOutputFolder, bundleName + ".packager.map");
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
bundleSourceMapOutput = path.join(sourcemapOutputFolder, bundleName + ".map");
|
|
29
|
+
}
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
case "ios": {
|
|
33
|
+
// see react-native-xcode.sh
|
|
34
|
+
// to match js bundle generated by Xcode and by Revopush cli we must respect SOURCEMAP_FILE value
|
|
35
|
+
// because it appears as //# sourceMappingURL value in a js bundle
|
|
36
|
+
const xcodeDotEnvValue = getXcodeDotEnvValue("SOURCEMAP_FILE");
|
|
37
|
+
const sourceMapFilename = xcodeDotEnvValue ? path.basename(xcodeDotEnvValue) : bundleName + ".map";
|
|
38
|
+
bundleSourceMapOutput = path.join(sourcemapOutputFolder, sourceMapFilename);
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
default:
|
|
42
|
+
throw new Error('Platform must be either "android", "ios" or "windows".');
|
|
43
|
+
}
|
|
44
|
+
return bundleSourceMapOutput;
|
|
45
|
+
}
|
|
46
|
+
exports.getBundleSourceMapOutput = getBundleSourceMapOutput;
|
|
47
|
+
async function runHermesEmitBinaryCommand(command, bundleName, outputFolder, sourcemapOutputFolder, extraHermesFlags, gradleFile) {
|
|
16
48
|
const hermesArgs = [];
|
|
17
49
|
const envNodeArgs = process.env.CODE_PUSH_NODE_ARGS;
|
|
18
50
|
if (typeof envNodeArgs !== "undefined") {
|
|
@@ -20,12 +52,13 @@ async function runHermesEmitBinaryCommand(bundleName, outputFolder, sourcemapOut
|
|
|
20
52
|
}
|
|
21
53
|
Array.prototype.push.apply(hermesArgs, [
|
|
22
54
|
"-emit-binary",
|
|
55
|
+
"-O",
|
|
23
56
|
"-out",
|
|
24
57
|
path.join(outputFolder, bundleName + ".hbc"),
|
|
25
58
|
path.join(outputFolder, bundleName),
|
|
26
59
|
...extraHermesFlags,
|
|
27
60
|
]);
|
|
28
|
-
if (
|
|
61
|
+
if (sourcemapOutputFolder) {
|
|
29
62
|
hermesArgs.push("-output-source-map");
|
|
30
63
|
}
|
|
31
64
|
console.log(chalk.cyan("Converting JS bundle to byte code via Hermes, running command:\n"));
|
|
@@ -60,8 +93,8 @@ async function runHermesEmitBinaryCommand(bundleName, outputFolder, sourcemapOut
|
|
|
60
93
|
});
|
|
61
94
|
});
|
|
62
95
|
});
|
|
63
|
-
}).then(() => {
|
|
64
|
-
if (!
|
|
96
|
+
}).then(async () => {
|
|
97
|
+
if (!sourcemapOutputFolder) {
|
|
65
98
|
// skip source map compose if source map is not enabled
|
|
66
99
|
return;
|
|
67
100
|
}
|
|
@@ -73,8 +106,32 @@ async function runHermesEmitBinaryCommand(bundleName, outputFolder, sourcemapOut
|
|
|
73
106
|
if (!fs.existsSync(jsCompilerSourceMapFile)) {
|
|
74
107
|
throw new Error(`sourcemap file ${jsCompilerSourceMapFile} is not found`);
|
|
75
108
|
}
|
|
109
|
+
const platformSourceMapOutput = await getBundleSourceMapOutput(command, bundleName, sourcemapOutputFolder);
|
|
76
110
|
return new Promise((resolve, reject) => {
|
|
77
|
-
|
|
111
|
+
let bundleSourceMapOutput = sourcemapOutputFolder;
|
|
112
|
+
let combinedSourceMapOutput = sourcemapOutputFolder;
|
|
113
|
+
if (!sourcemapOutputFolder.endsWith(".map")) {
|
|
114
|
+
bundleSourceMapOutput = platformSourceMapOutput;
|
|
115
|
+
switch (command.platform) {
|
|
116
|
+
case "android": {
|
|
117
|
+
combinedSourceMapOutput = path.join(sourcemapOutputFolder, bundleName + ".map");
|
|
118
|
+
break;
|
|
119
|
+
}
|
|
120
|
+
case "ios": {
|
|
121
|
+
combinedSourceMapOutput = bundleSourceMapOutput;
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
default:
|
|
125
|
+
throw new Error('Platform must be either "android", "ios" or "windows".');
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
const composeSourceMapsArgs = [
|
|
129
|
+
composeSourceMapsPath,
|
|
130
|
+
bundleSourceMapOutput,
|
|
131
|
+
jsCompilerSourceMapFile,
|
|
132
|
+
"-o",
|
|
133
|
+
combinedSourceMapOutput,
|
|
134
|
+
];
|
|
78
135
|
// https://github.com/facebook/react-native/blob/master/react.gradle#L211
|
|
79
136
|
// https://github.com/facebook/react-native/blob/master/scripts/react-native-xcode.sh#L178
|
|
80
137
|
// packager.sourcemap.map + hbc.sourcemap.map = sourcemap.map
|
|
@@ -103,6 +160,38 @@ async function runHermesEmitBinaryCommand(bundleName, outputFolder, sourcemapOut
|
|
|
103
160
|
});
|
|
104
161
|
}
|
|
105
162
|
exports.runHermesEmitBinaryCommand = runHermesEmitBinaryCommand;
|
|
163
|
+
function getXcodeDotEnvValue(key) {
|
|
164
|
+
const xcodeEnvs = loadEnvAsMap([path.join("ios", ".xcode.env.local"), path.join("ios", ".xcode.env.local")]);
|
|
165
|
+
return xcodeEnvs.get(key);
|
|
166
|
+
}
|
|
167
|
+
exports.getXcodeDotEnvValue = getXcodeDotEnvValue;
|
|
168
|
+
async function getMinifyParams(command) {
|
|
169
|
+
const isHermes = await isHermesEnabled(command);
|
|
170
|
+
switch (command.platform) {
|
|
171
|
+
case "android": {
|
|
172
|
+
// android always explicitly pass --minify true/false
|
|
173
|
+
// TaskConfiguration it.minifyEnabled.set(!isHermesEnabledInThisVariant)
|
|
174
|
+
return ["--minify", !isHermes];
|
|
175
|
+
}
|
|
176
|
+
case "ios": {
|
|
177
|
+
//if [[ $USE_HERMES != false && $DEV == false ]]; then
|
|
178
|
+
// EXTRA_ARGS+=("--minify" "false")
|
|
179
|
+
// fi
|
|
180
|
+
// ios does pass --minify false only if Hermes enables and does pass anything otherwise
|
|
181
|
+
return isHermes ? ["--minify", false] : [];
|
|
182
|
+
}
|
|
183
|
+
default:
|
|
184
|
+
throw new Error('Platform must be either "android", "ios" or "windows".');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
exports.getMinifyParams = getMinifyParams;
|
|
188
|
+
async function isHermesEnabled(command, platform = command.platform.toLowerCase()) {
|
|
189
|
+
// Check if we have to run hermes to compile JS to Byte Code if Hermes is enabled in Podfile and we're releasing an iOS build
|
|
190
|
+
const isAndroidHermesEnabled = await getAndroidHermesEnabled(command.gradleFile);
|
|
191
|
+
const isIOSHermesEnabled = getiOSHermesEnabled(command.podFile);
|
|
192
|
+
return command.useHermes || (platform === "android" && isAndroidHermesEnabled) || (platform === "ios" && isIOSHermesEnabled);
|
|
193
|
+
}
|
|
194
|
+
exports.isHermesEnabled = isHermesEnabled;
|
|
106
195
|
function parseBuildGradleFile(gradleFile) {
|
|
107
196
|
let buildGradlePath = path.join("android", "app");
|
|
108
197
|
if (gradleFile) {
|
|
@@ -118,6 +207,45 @@ function parseBuildGradleFile(gradleFile) {
|
|
|
118
207
|
throw new Error(`Unable to parse the "${buildGradlePath}" file. Please ensure it is a well-formed Gradle file.`);
|
|
119
208
|
});
|
|
120
209
|
}
|
|
210
|
+
function parseGradlePropertiesFile(gradleFile) {
|
|
211
|
+
let gradlePropsPath = path.join("android", "gradle.properties");
|
|
212
|
+
try {
|
|
213
|
+
if (gradleFile) {
|
|
214
|
+
const base = gradleFile;
|
|
215
|
+
const stat = fs.lstatSync(base);
|
|
216
|
+
if (stat.isDirectory()) {
|
|
217
|
+
if (path.basename(base) === "app") {
|
|
218
|
+
gradlePropsPath = path.join(base, "..", "gradle.properties");
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
gradlePropsPath = path.join(base, "gradle.properties");
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
gradlePropsPath = path.join(path.dirname(base), "..", "gradle.properties");
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
catch { }
|
|
230
|
+
gradlePropsPath = path.normalize(gradlePropsPath);
|
|
231
|
+
if ((0, file_utils_1.fileDoesNotExistOrIsDirectory)(gradlePropsPath)) {
|
|
232
|
+
throw new Error(`Unable to find gradle.properties file "${gradlePropsPath}".`);
|
|
233
|
+
}
|
|
234
|
+
const text = fs.readFileSync(gradlePropsPath, "utf8");
|
|
235
|
+
const props = {};
|
|
236
|
+
for (const rawLine of text.split(/\r?\n/)) {
|
|
237
|
+
const line = rawLine.trim();
|
|
238
|
+
if (!line || line.startsWith("#"))
|
|
239
|
+
continue;
|
|
240
|
+
const m = line.match(/^([^=\s]+)\s*=\s*(.*)$/);
|
|
241
|
+
if (m) {
|
|
242
|
+
const key = m[1].trim();
|
|
243
|
+
const val = m[2].trim();
|
|
244
|
+
props[key] = val;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return props;
|
|
248
|
+
}
|
|
121
249
|
async function getHermesCommandFromGradle(gradleFile) {
|
|
122
250
|
const buildGradle = await parseBuildGradleFile(gradleFile);
|
|
123
251
|
const hermesCommandProperty = Array.from(buildGradle["project.ext.react"] || []).find((prop) => prop.trim().startsWith("hermesCommand:"));
|
|
@@ -128,12 +256,30 @@ async function getHermesCommandFromGradle(gradleFile) {
|
|
|
128
256
|
return "";
|
|
129
257
|
}
|
|
130
258
|
}
|
|
131
|
-
function getAndroidHermesEnabled(gradleFile) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
259
|
+
async function getAndroidHermesEnabled(gradleFile) {
|
|
260
|
+
try {
|
|
261
|
+
const props = parseGradlePropertiesFile(gradleFile);
|
|
262
|
+
if (typeof props.hermesEnabled !== "undefined") {
|
|
263
|
+
const v = String(props.hermesEnabled).trim().toLowerCase();
|
|
264
|
+
if (v === "true")
|
|
265
|
+
return true;
|
|
266
|
+
if (v === "false")
|
|
267
|
+
return false;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
catch { }
|
|
271
|
+
try {
|
|
272
|
+
const buildGradle = await parseBuildGradleFile(gradleFile);
|
|
273
|
+
const lines = Array.from(buildGradle["project.ext.react"] || []);
|
|
274
|
+
if (lines.some((l) => /\benableHermes\s*:\s*true\b/.test(l)))
|
|
275
|
+
return true;
|
|
276
|
+
if (lines.some((l) => /\benableHermes\s*:\s*false\b/.test(l)))
|
|
277
|
+
return false;
|
|
278
|
+
}
|
|
279
|
+
catch { }
|
|
280
|
+
const rnVersion = (0, semver_1.coerce)(getReactNativeVersion())?.version;
|
|
281
|
+
return rnVersion && (0, semver_1.compare)(rnVersion, "0.70.0") >= 0;
|
|
135
282
|
}
|
|
136
|
-
exports.getAndroidHermesEnabled = getAndroidHermesEnabled;
|
|
137
283
|
function getiOSHermesEnabled(podFile) {
|
|
138
284
|
let podPath = path.join("ios", "Podfile");
|
|
139
285
|
if (podFile) {
|
|
@@ -144,13 +290,29 @@ function getiOSHermesEnabled(podFile) {
|
|
|
144
290
|
}
|
|
145
291
|
try {
|
|
146
292
|
const podFileContents = fs.readFileSync(podPath).toString();
|
|
147
|
-
|
|
293
|
+
const hasTrue = /([^#\n]*:?hermes_enabled(\s+|\n+)?(=>|:)(\s+|\n+)?true)/.test(podFileContents);
|
|
294
|
+
if (hasTrue)
|
|
295
|
+
return true;
|
|
296
|
+
const hasFalse = /([^#\n]*:?hermes_enabled(\s+|\n+)?(=>|:)(\s+|\n+)?false)/.test(podFileContents);
|
|
297
|
+
if (hasFalse)
|
|
298
|
+
return false;
|
|
299
|
+
const rnVersion = (0, semver_1.coerce)(getReactNativeVersion())?.version;
|
|
300
|
+
return rnVersion && (0, semver_1.compare)(rnVersion, "0.70.0") >= 0;
|
|
148
301
|
}
|
|
149
302
|
catch (error) {
|
|
150
303
|
throw error;
|
|
151
304
|
}
|
|
152
305
|
}
|
|
153
|
-
|
|
306
|
+
function loadEnvAsMap(envPaths = []) {
|
|
307
|
+
const merged = {};
|
|
308
|
+
for (const envPath of envPaths) {
|
|
309
|
+
if (fs.existsSync(envPath)) {
|
|
310
|
+
Object.assign(merged, dotenv.parse(fs.readFileSync(envPath))); // later files override earlier ones
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// fallback to process.env for anything missing
|
|
314
|
+
return new Map([...Object.entries(process.env), ...Object.entries(merged)]);
|
|
315
|
+
}
|
|
154
316
|
function getHermesOSBin() {
|
|
155
317
|
switch (process.platform) {
|
|
156
318
|
case "win32":
|
|
@@ -184,7 +346,8 @@ async function getHermesCommand(gradleFile) {
|
|
|
184
346
|
}
|
|
185
347
|
};
|
|
186
348
|
// Hermes is bundled with react-native since 0.69
|
|
187
|
-
const
|
|
349
|
+
const reactNativePath = getReactNativePackagePath();
|
|
350
|
+
const bundledHermesEngine = path.join(reactNativePath, "sdks", "hermesc", getHermesOSBin(), getHermesOSExe());
|
|
188
351
|
if (fileExists(bundledHermesEngine)) {
|
|
189
352
|
return bundledHermesEngine;
|
|
190
353
|
}
|
|
@@ -193,12 +356,13 @@ async function getHermesCommand(gradleFile) {
|
|
|
193
356
|
return path.join("android", "app", gradleHermesCommand.replace("%OS-BIN%", getHermesOSBin()));
|
|
194
357
|
}
|
|
195
358
|
else {
|
|
359
|
+
const nodeModulesPath = getNodeModulesPath(reactNativePath);
|
|
196
360
|
// assume if hermes-engine exists it should be used instead of hermesvm
|
|
197
|
-
const hermesEngine = path.join(
|
|
361
|
+
const hermesEngine = path.join(nodeModulesPath, "hermes-engine", getHermesOSBin(), getHermesOSExe());
|
|
198
362
|
if (fileExists(hermesEngine)) {
|
|
199
363
|
return hermesEngine;
|
|
200
364
|
}
|
|
201
|
-
return path.join(
|
|
365
|
+
return path.join(nodeModulesPath, "hermesvm", getHermesOSBin(), "hermes");
|
|
202
366
|
}
|
|
203
367
|
}
|
|
204
368
|
function getComposeSourceMapsPath() {
|
|
@@ -209,6 +373,13 @@ function getComposeSourceMapsPath() {
|
|
|
209
373
|
}
|
|
210
374
|
return null;
|
|
211
375
|
}
|
|
376
|
+
function getNodeModulesPath(reactNativePath) {
|
|
377
|
+
const nodeModulesPath = path.dirname(reactNativePath);
|
|
378
|
+
if (directoryExistsSync(nodeModulesPath)) {
|
|
379
|
+
return nodeModulesPath;
|
|
380
|
+
}
|
|
381
|
+
return path.join("node_modules");
|
|
382
|
+
}
|
|
212
383
|
function getReactNativePackagePath() {
|
|
213
384
|
const result = childProcess.spawnSync("node", ["--print", "require.resolve('react-native/package.json')"]);
|
|
214
385
|
const packagePath = path.dirname(result.stdout.toString());
|
|
@@ -217,6 +388,7 @@ function getReactNativePackagePath() {
|
|
|
217
388
|
}
|
|
218
389
|
return path.join("node_modules", "react-native");
|
|
219
390
|
}
|
|
391
|
+
exports.getReactNativePackagePath = getReactNativePackagePath;
|
|
220
392
|
function directoryExistsSync(dirname) {
|
|
221
393
|
try {
|
|
222
394
|
return fs.statSync(dirname).isDirectory();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revopush/code-push-cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.7",
|
|
4
4
|
"description": "Management CLI for the CodePush service",
|
|
5
5
|
"main": "./script/cli.js",
|
|
6
6
|
"scripts": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"backslash": "^0.2.0",
|
|
27
27
|
"chalk": "^4.1.2",
|
|
28
28
|
"cli-table": "^0.3.11",
|
|
29
|
+
"dotenv": "^17.2.1",
|
|
29
30
|
"email-validator": "^2.0.4",
|
|
30
31
|
"gradle-to-js": "2.0.1",
|
|
31
32
|
"jsonwebtoken": "^9.0.2",
|