@hot-updater/apple-helper 1.2.0-rc.0 → 1.2.0-rc.2
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/dist/index.cjs +208 -112
- package/dist/index.d.cts +6 -0
- package/dist/index.d.mts +6 -0
- package/dist/index.mjs +209 -113
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -154,7 +154,7 @@ var AscCommandError = class extends Error {
|
|
|
154
154
|
this.exitCode = exitCode;
|
|
155
155
|
}
|
|
156
156
|
};
|
|
157
|
-
const TERMINATION_SIGNALS$
|
|
157
|
+
const TERMINATION_SIGNALS$3 = [
|
|
158
158
|
"SIGHUP",
|
|
159
159
|
"SIGINT",
|
|
160
160
|
"SIGTERM"
|
|
@@ -178,10 +178,10 @@ const createWorkDirectory = async () => {
|
|
|
178
178
|
};
|
|
179
179
|
const stop = () => {
|
|
180
180
|
process.off("exit", remove);
|
|
181
|
-
for (const signal of TERMINATION_SIGNALS$
|
|
181
|
+
for (const signal of TERMINATION_SIGNALS$3) process.off(signal, onSignal);
|
|
182
182
|
};
|
|
183
183
|
process.on("exit", remove);
|
|
184
|
-
for (const signal of TERMINATION_SIGNALS$
|
|
184
|
+
for (const signal of TERMINATION_SIGNALS$3) process.on(signal, onSignal);
|
|
185
185
|
for (const directory of [
|
|
186
186
|
"home",
|
|
187
187
|
"session",
|
|
@@ -578,8 +578,55 @@ const resolvePodInstallPlan = ({ version, env }) => {
|
|
|
578
578
|
};
|
|
579
579
|
//#endregion
|
|
580
580
|
//#region src/utils/createRandomTmpDir.ts
|
|
581
|
+
const TERMINATION_SIGNALS$2 = [
|
|
582
|
+
"SIGHUP",
|
|
583
|
+
"SIGINT",
|
|
584
|
+
"SIGTERM"
|
|
585
|
+
];
|
|
586
|
+
const REMOVE_OPTIONS = {
|
|
587
|
+
force: true,
|
|
588
|
+
recursive: true,
|
|
589
|
+
maxRetries: 3
|
|
590
|
+
};
|
|
591
|
+
const liveDirectories = /* @__PURE__ */ new Set();
|
|
592
|
+
const onSignal = (signal) => {
|
|
593
|
+
removeLiveDirectories();
|
|
594
|
+
if (process.listenerCount(signal) === 0) process.kill(process.pid, signal);
|
|
595
|
+
};
|
|
596
|
+
const removeLiveDirectories = () => {
|
|
597
|
+
for (const directory of liveDirectories) try {
|
|
598
|
+
(0, node_fs.rmSync)(directory, REMOVE_OPTIONS);
|
|
599
|
+
} catch {}
|
|
600
|
+
liveDirectories.clear();
|
|
601
|
+
stopListening();
|
|
602
|
+
};
|
|
603
|
+
const startListening = () => {
|
|
604
|
+
process.on("exit", removeLiveDirectories);
|
|
605
|
+
for (const signal of TERMINATION_SIGNALS$2) process.on(signal, onSignal);
|
|
606
|
+
};
|
|
607
|
+
const stopListening = () => {
|
|
608
|
+
process.off("exit", removeLiveDirectories);
|
|
609
|
+
for (const signal of TERMINATION_SIGNALS$2) process.off(signal, onSignal);
|
|
610
|
+
};
|
|
611
|
+
/**
|
|
612
|
+
* Creates a directory in the system's temporary directory, which
|
|
613
|
+
* `removeTmpDir` removes, and which is otherwise removed when the process
|
|
614
|
+
* exits or is stopped by a signal.
|
|
615
|
+
*/
|
|
581
616
|
const createRandomTmpDir = async (prefix = "apple-helper-") => {
|
|
582
|
-
|
|
617
|
+
const directory = await (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), prefix));
|
|
618
|
+
if (liveDirectories.size === 0) startListening();
|
|
619
|
+
liveDirectories.add(directory);
|
|
620
|
+
return directory;
|
|
621
|
+
};
|
|
622
|
+
/**
|
|
623
|
+
* Removes a directory `createRandomTmpDir` created. It stays tracked until
|
|
624
|
+
* it is gone, so a signal during a removal that takes seconds, such as
|
|
625
|
+
* DerivedData's, still finishes it.
|
|
626
|
+
*/
|
|
627
|
+
const removeTmpDir = async (directory) => {
|
|
628
|
+
await (0, node_fs_promises.rm)(directory, REMOVE_OPTIONS);
|
|
629
|
+
if (liveDirectories.delete(directory) && liveDirectories.size === 0) stopListening();
|
|
583
630
|
};
|
|
584
631
|
//#endregion
|
|
585
632
|
//#region src/utils/platform.ts
|
|
@@ -883,53 +930,62 @@ const buildSettingsOverScheme = ({ minBundleId, authenticationArgs }) => ({
|
|
|
883
930
|
});
|
|
884
931
|
//#endregion
|
|
885
932
|
//#region src/builder/archiveXcodeProject.ts
|
|
886
|
-
|
|
933
|
+
/**
|
|
934
|
+
* Archives the scheme into `archiveDirectory`. The build's xcconfig is
|
|
935
|
+
* written to a temporary directory, removed whether the archive succeeds or
|
|
936
|
+
* not.
|
|
937
|
+
*/
|
|
938
|
+
const archiveXcodeProject = async ({ sourceDir, archiveDirectory, platform, installPods, destination, extraParams, configuration, xcodeScheme, xcconfig, logPrefix, minBundleId, authenticationArgs }) => {
|
|
887
939
|
if (installPods) await installPodsIfNeeded(sourceDir);
|
|
888
940
|
const xcodeProject = await parseXcodeProjectInfo(sourceDir);
|
|
889
|
-
const tmpDir = await createRandomTmpDir();
|
|
890
941
|
const archiveName = `${xcodeProject.name.replace(".xcworkspace", "").replace(".xcodeproj", "")}.xcarchive`;
|
|
891
|
-
const archivePath = path.default.join(
|
|
892
|
-
const
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
942
|
+
const archivePath = path.default.join(archiveDirectory, archiveName);
|
|
943
|
+
const tmpDir = await createRandomTmpDir();
|
|
944
|
+
try {
|
|
945
|
+
const build = await writeBuildXcconfig({
|
|
946
|
+
directory: tmpDir,
|
|
947
|
+
sourceDir,
|
|
948
|
+
xcconfig,
|
|
949
|
+
extraParams,
|
|
950
|
+
settings: buildSettingsOverScheme({
|
|
951
|
+
minBundleId,
|
|
952
|
+
authenticationArgs
|
|
953
|
+
})
|
|
954
|
+
});
|
|
955
|
+
const archiveArgs = prepareArchiveArgs({
|
|
956
|
+
authenticationArgs,
|
|
898
957
|
minBundleId,
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
extraParams: build.extraParams,
|
|
911
|
-
destination,
|
|
912
|
-
xcconfig: build.xcconfig,
|
|
913
|
-
xcodeScheme
|
|
914
|
-
});
|
|
915
|
-
_hot_updater_cli_tools.p.log.info(`Xcode Archive Settings:
|
|
958
|
+
archivePath,
|
|
959
|
+
platform,
|
|
960
|
+
sourceDir,
|
|
961
|
+
xcodeProject,
|
|
962
|
+
configuration,
|
|
963
|
+
extraParams: build.extraParams,
|
|
964
|
+
destination,
|
|
965
|
+
xcconfig: build.xcconfig,
|
|
966
|
+
xcodeScheme
|
|
967
|
+
});
|
|
968
|
+
_hot_updater_cli_tools.p.log.info(`Xcode Archive Settings:
|
|
916
969
|
Project ${xcodeProject.name}
|
|
917
970
|
Scheme ${xcodeScheme}
|
|
918
971
|
Platform ${platform}
|
|
919
972
|
Command xcodebuild ${archiveArgs.join(" ")}
|
|
920
973
|
`);
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
974
|
+
try {
|
|
975
|
+
await runXcodebuildWithLogging({
|
|
976
|
+
args: archiveArgs,
|
|
977
|
+
env: { HOT_UPDATER_MIN_BUNDLE_ID: minBundleId },
|
|
978
|
+
failureMessage: "Archive failed",
|
|
979
|
+
logPrefix,
|
|
980
|
+
sourceDir,
|
|
981
|
+
successMessage: "Archive completed successfully"
|
|
982
|
+
});
|
|
983
|
+
return { archivePath };
|
|
984
|
+
} catch (error) {
|
|
985
|
+
throw prettifyXcodebuildError(error);
|
|
986
|
+
}
|
|
987
|
+
} finally {
|
|
988
|
+
await removeTmpDir(tmpDir);
|
|
933
989
|
}
|
|
934
990
|
};
|
|
935
991
|
const prepareArchiveArgs = ({ xcodeScheme, archivePath, platform, sourceDir, xcodeProject, configuration = "Release", xcconfig, extraParams, destination = [], minBundleId, authenticationArgs }) => {
|
|
@@ -962,69 +1018,83 @@ const prepareArchiveArgs = ({ xcodeScheme, archivePath, platform, sourceDir, xco
|
|
|
962
1018
|
};
|
|
963
1019
|
//#endregion
|
|
964
1020
|
//#region src/builder/buildXcodeProject.ts
|
|
965
|
-
|
|
1021
|
+
/**
|
|
1022
|
+
* Builds the scheme in a temporary DerivedData directory, copies the built
|
|
1023
|
+
* `.app` to `outputDirectory`, and removes DerivedData, which takes 10 GB or
|
|
1024
|
+
* more, whether the build succeeds or not.
|
|
1025
|
+
*/
|
|
1026
|
+
const buildXcodeProject = async ({ sourceDir, outputDirectory, platform, xcodeScheme, configuration, deviceType, logPrefix, destination = [], useGenericDestination = false, installPods, extraParams, minBundleId, authenticationArgs }) => {
|
|
966
1027
|
if (installPods) await installPodsIfNeeded(sourceDir);
|
|
967
1028
|
const xcodeProject = await parseXcodeProjectInfo(sourceDir);
|
|
968
|
-
const
|
|
969
|
-
const resolvedDestinations = resolveDestinations({
|
|
970
|
-
destinations: destination,
|
|
971
|
-
useGeneric: useGenericDestination
|
|
972
|
-
});
|
|
973
|
-
if (resolvedDestinations.length === 0) resolvedDestinations.push(getDefaultDestination({
|
|
974
|
-
deviceType,
|
|
975
|
-
platform,
|
|
976
|
-
useGeneric: useGenericDestination
|
|
977
|
-
}));
|
|
978
|
-
const build = await writeBuildXcconfig({
|
|
979
|
-
directory: await createRandomTmpDir(),
|
|
980
|
-
sourceDir,
|
|
981
|
-
extraParams,
|
|
982
|
-
settings: buildSettingsOverScheme({
|
|
983
|
-
minBundleId,
|
|
984
|
-
authenticationArgs
|
|
985
|
-
})
|
|
986
|
-
});
|
|
987
|
-
const buildArgs = prepareBuildArgs({
|
|
988
|
-
authenticationArgs,
|
|
989
|
-
xcconfig: build.xcconfig,
|
|
990
|
-
minBundleId,
|
|
991
|
-
configuration,
|
|
992
|
-
derivedDataPath,
|
|
993
|
-
deviceType,
|
|
994
|
-
resolvedDestinations,
|
|
995
|
-
extraParams: build.extraParams,
|
|
996
|
-
platform,
|
|
997
|
-
xcodeScheme,
|
|
998
|
-
sourceDir,
|
|
999
|
-
xcodeProject
|
|
1000
|
-
});
|
|
1001
|
-
_hot_updater_cli_tools.p.log.info(`Xcode Build Settings:
|
|
1002
|
-
Project ${xcodeProject.name}
|
|
1003
|
-
Scheme ${xcodeScheme}
|
|
1004
|
-
Configuration ${configuration}
|
|
1005
|
-
Platform ${platform}
|
|
1006
|
-
Device Type ${deviceType}
|
|
1007
|
-
Command xcodebuild ${buildArgs.join(" ")}
|
|
1008
|
-
`);
|
|
1029
|
+
const tmpDir = await createRandomTmpDir();
|
|
1009
1030
|
try {
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1031
|
+
const derivedDataPath = path.default.join(tmpDir, "DerivedData");
|
|
1032
|
+
const resolvedDestinations = resolveDestinations({
|
|
1033
|
+
destinations: destination,
|
|
1034
|
+
useGeneric: useGenericDestination
|
|
1035
|
+
});
|
|
1036
|
+
if (resolvedDestinations.length === 0) resolvedDestinations.push(getDefaultDestination({
|
|
1037
|
+
deviceType,
|
|
1038
|
+
platform,
|
|
1039
|
+
useGeneric: useGenericDestination
|
|
1040
|
+
}));
|
|
1041
|
+
const build = await writeBuildXcconfig({
|
|
1042
|
+
directory: tmpDir,
|
|
1013
1043
|
sourceDir,
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1044
|
+
extraParams,
|
|
1045
|
+
settings: buildSettingsOverScheme({
|
|
1046
|
+
minBundleId,
|
|
1047
|
+
authenticationArgs
|
|
1048
|
+
})
|
|
1017
1049
|
});
|
|
1018
|
-
|
|
1050
|
+
const buildArgs = prepareBuildArgs({
|
|
1051
|
+
authenticationArgs,
|
|
1052
|
+
xcconfig: build.xcconfig,
|
|
1053
|
+
minBundleId,
|
|
1019
1054
|
configuration,
|
|
1020
1055
|
derivedDataPath,
|
|
1056
|
+
deviceType,
|
|
1021
1057
|
resolvedDestinations,
|
|
1058
|
+
extraParams: build.extraParams,
|
|
1059
|
+
platform,
|
|
1022
1060
|
xcodeScheme,
|
|
1023
1061
|
sourceDir,
|
|
1024
1062
|
xcodeProject
|
|
1025
1063
|
});
|
|
1026
|
-
|
|
1027
|
-
|
|
1064
|
+
_hot_updater_cli_tools.p.log.info(`Xcode Build Settings:
|
|
1065
|
+
Project ${xcodeProject.name}
|
|
1066
|
+
Scheme ${xcodeScheme}
|
|
1067
|
+
Configuration ${configuration}
|
|
1068
|
+
Platform ${platform}
|
|
1069
|
+
Device Type ${deviceType}
|
|
1070
|
+
Command xcodebuild ${buildArgs.join(" ")}
|
|
1071
|
+
`);
|
|
1072
|
+
let builtAppPath;
|
|
1073
|
+
try {
|
|
1074
|
+
await runXcodebuildWithLogging({
|
|
1075
|
+
args: buildArgs,
|
|
1076
|
+
env: { HOT_UPDATER_MIN_BUNDLE_ID: minBundleId },
|
|
1077
|
+
sourceDir,
|
|
1078
|
+
logPrefix,
|
|
1079
|
+
successMessage: "Build completed successfully",
|
|
1080
|
+
failureMessage: "Build failed"
|
|
1081
|
+
});
|
|
1082
|
+
({appPath: builtAppPath} = await getBuildSettings({
|
|
1083
|
+
configuration,
|
|
1084
|
+
derivedDataPath,
|
|
1085
|
+
resolvedDestinations,
|
|
1086
|
+
xcodeScheme,
|
|
1087
|
+
sourceDir,
|
|
1088
|
+
xcodeProject
|
|
1089
|
+
}));
|
|
1090
|
+
} catch (error) {
|
|
1091
|
+
throw prettifyXcodebuildError(error);
|
|
1092
|
+
}
|
|
1093
|
+
const appPath = path.default.join(outputDirectory, path.default.basename(builtAppPath));
|
|
1094
|
+
await fs.default.promises.cp(builtAppPath, appPath, { recursive: true });
|
|
1095
|
+
return { appPath };
|
|
1096
|
+
} finally {
|
|
1097
|
+
await removeTmpDir(tmpDir);
|
|
1028
1098
|
}
|
|
1029
1099
|
};
|
|
1030
1100
|
const prepareBuildArgs = ({ xcodeProject, sourceDir, platform, xcodeScheme, configuration, deviceType, resolvedDestinations, derivedDataPath, extraParams, minBundleId, authenticationArgs, xcconfig }) => {
|
|
@@ -1081,8 +1151,8 @@ const getBuildSettings = async ({ xcodeProject, sourceDir, xcodeScheme, configur
|
|
|
1081
1151
|
};
|
|
1082
1152
|
//#endregion
|
|
1083
1153
|
//#region src/builder/exportXcodeArchive.ts
|
|
1084
|
-
|
|
1085
|
-
|
|
1154
|
+
/** Exports the archive into `exportPath`. */
|
|
1155
|
+
const exportXcodeArchive = async ({ archivePath, exportPath, sourceDir, exportExtraParams, exportOptionsPlist, logPrefix, authenticationArgs }) => {
|
|
1086
1156
|
const exportArgs = prepareExportArgs({
|
|
1087
1157
|
authenticationArgs,
|
|
1088
1158
|
archivePath,
|
|
@@ -2112,21 +2182,41 @@ const readBuiltApp = async (appPath) => {
|
|
|
2112
2182
|
* Builds a simulator `.app` for a `simulator` scheme, and otherwise archives
|
|
2113
2183
|
* and exports an `.ipa`, or returns the `.xcarchive` of a scheme it cannot
|
|
2114
2184
|
* export: one with neither `exportOptionsPlist` nor `signing.ascApiKey`.
|
|
2185
|
+
*
|
|
2186
|
+
* The artifact is in a temporary `buildDirectory`, which `dispose` removes
|
|
2187
|
+
* once the caller has copied it out. A failed build removes it, and every
|
|
2188
|
+
* other directory the build used, itself.
|
|
2115
2189
|
*/
|
|
2116
2190
|
const buildIos = async ({ schemeConfig, minBundleId = (0, _hot_updater_cli_tools.createMinBundleId)(), credentials }) => {
|
|
2117
2191
|
await assertXcodebuildExist();
|
|
2118
|
-
|
|
2192
|
+
if (schemeConfig.simulator && schemeConfig.destination.length) {
|
|
2193
|
+
_hot_updater_cli_tools.p.log.error("The scheme option 'simulator' is not compatible with the 'destination' option.");
|
|
2194
|
+
process.exit(1);
|
|
2195
|
+
}
|
|
2119
2196
|
const buildDirectory = await createRandomTmpDir();
|
|
2120
|
-
|
|
2197
|
+
try {
|
|
2198
|
+
return {
|
|
2199
|
+
...await buildInto({
|
|
2200
|
+
schemeConfig,
|
|
2201
|
+
minBundleId,
|
|
2202
|
+
credentials,
|
|
2203
|
+
buildDirectory
|
|
2204
|
+
}),
|
|
2205
|
+
dispose: () => removeTmpDir(buildDirectory)
|
|
2206
|
+
};
|
|
2207
|
+
} catch (error) {
|
|
2208
|
+
await removeTmpDir(buildDirectory);
|
|
2209
|
+
throw error;
|
|
2210
|
+
}
|
|
2211
|
+
};
|
|
2212
|
+
const buildInto = async ({ schemeConfig, minBundleId, credentials, buildDirectory }) => {
|
|
2213
|
+
const iosProjectRoot = path.default.join((0, _hot_updater_cli_tools.getCwd)(), "ios");
|
|
2121
2214
|
if (schemeConfig.simulator) {
|
|
2122
|
-
if (schemeConfig.destination.length) {
|
|
2123
|
-
_hot_updater_cli_tools.p.log.error("The scheme option 'simulator' is not compatible with the 'destination' option.");
|
|
2124
|
-
process.exit(1);
|
|
2125
|
-
}
|
|
2126
2215
|
const appDir = path.default.join(buildDirectory, "app");
|
|
2127
2216
|
await fs.default.promises.mkdir(appDir, { recursive: true });
|
|
2128
2217
|
const { appPath } = await buildXcodeProject({
|
|
2129
2218
|
sourceDir: iosProjectRoot,
|
|
2219
|
+
outputDirectory: appDir,
|
|
2130
2220
|
logPrefix: `ios-${schemeConfig.hotUpdaterSchemeName}-build`,
|
|
2131
2221
|
platform: schemeConfig.platform,
|
|
2132
2222
|
xcodeScheme: schemeConfig.scheme,
|
|
@@ -2137,13 +2227,11 @@ const buildIos = async ({ schemeConfig, minBundleId = (0, _hot_updater_cli_tools
|
|
|
2137
2227
|
useGenericDestination: true,
|
|
2138
2228
|
minBundleId
|
|
2139
2229
|
});
|
|
2140
|
-
const finalAppPath = path.default.join(appDir, path.default.basename(appPath));
|
|
2141
|
-
await fs.default.promises.cp(appPath, finalAppPath, { recursive: true });
|
|
2142
2230
|
_hot_updater_cli_tools.p.log.success(`.app file created: ${path.default.basename(appPath)}`);
|
|
2143
2231
|
return {
|
|
2144
2232
|
buildDirectory,
|
|
2145
|
-
buildArtifactPath:
|
|
2146
|
-
builtApp: await readBuiltApp(
|
|
2233
|
+
buildArtifactPath: appPath,
|
|
2234
|
+
builtApp: await readBuiltApp(appPath)
|
|
2147
2235
|
};
|
|
2148
2236
|
} else {
|
|
2149
2237
|
const signing = await resolveXcodeSigning({
|
|
@@ -2177,7 +2265,9 @@ const archiveAndExport = async ({ schemeConfig, minBundleId, buildDirectory, aut
|
|
|
2177
2265
|
const iosProjectRoot = path.default.join((0, _hot_updater_cli_tools.getCwd)(), "ios");
|
|
2178
2266
|
const archiveDir = path.default.join(buildDirectory, "archive");
|
|
2179
2267
|
const exportDir = path.default.join(buildDirectory, "export");
|
|
2268
|
+
await fs.default.promises.mkdir(archiveDir, { recursive: true });
|
|
2180
2269
|
const { archivePath } = await archiveXcodeProject({
|
|
2270
|
+
archiveDirectory: archiveDir,
|
|
2181
2271
|
authenticationArgs,
|
|
2182
2272
|
minBundleId,
|
|
2183
2273
|
platform: schemeConfig.platform,
|
|
@@ -2190,9 +2280,7 @@ const archiveAndExport = async ({ schemeConfig, minBundleId, buildDirectory, aut
|
|
|
2190
2280
|
installPods: schemeConfig.installPods,
|
|
2191
2281
|
logPrefix: `ios-${schemeConfig.hotUpdaterSchemeName}-build-archive`
|
|
2192
2282
|
});
|
|
2193
|
-
const
|
|
2194
|
-
await fs.default.promises.cp(archivePath, finalArchivePath, { recursive: true });
|
|
2195
|
-
const appFromArchive = extractAppFromXcarchive(finalArchivePath);
|
|
2283
|
+
const appFromArchive = extractAppFromXcarchive(archivePath);
|
|
2196
2284
|
const archivedAppPath = appFromArchive ? path.default.join(archiveDir, path.default.basename(appFromArchive)) : void 0;
|
|
2197
2285
|
if (appFromArchive && archivedAppPath) {
|
|
2198
2286
|
await fs.default.promises.cp(appFromArchive, archivedAppPath, { recursive: true });
|
|
@@ -2200,20 +2288,28 @@ const archiveAndExport = async ({ schemeConfig, minBundleId, buildDirectory, aut
|
|
|
2200
2288
|
}
|
|
2201
2289
|
if (!schemeConfig.exportOptionsPlist && !authenticationArgs) return {
|
|
2202
2290
|
buildDirectory,
|
|
2203
|
-
buildArtifactPath:
|
|
2291
|
+
buildArtifactPath: archivePath,
|
|
2204
2292
|
builtApp: archivedAppPath ? await readBuiltApp(archivedAppPath) : void 0
|
|
2205
2293
|
};
|
|
2206
2294
|
await fs.default.promises.mkdir(exportDir, { recursive: true });
|
|
2207
|
-
const
|
|
2208
|
-
const { exportPath } = await exportXcodeArchive({
|
|
2295
|
+
const exportArchive = (exportOptionsPlist) => exportXcodeArchive({
|
|
2209
2296
|
archivePath,
|
|
2297
|
+
exportPath: exportDir,
|
|
2210
2298
|
authenticationArgs,
|
|
2211
2299
|
exportExtraParams: schemeConfig.exportExtraParams,
|
|
2212
2300
|
exportOptionsPlist,
|
|
2213
2301
|
sourceDir: iosProjectRoot,
|
|
2214
2302
|
logPrefix: `ios-${schemeConfig.hotUpdaterSchemeName}-build-export`
|
|
2215
2303
|
});
|
|
2216
|
-
|
|
2304
|
+
if (schemeConfig.exportOptionsPlist) await exportArchive(schemeConfig.exportOptionsPlist);
|
|
2305
|
+
else {
|
|
2306
|
+
const exportOptionsDir = await createRandomTmpDir();
|
|
2307
|
+
try {
|
|
2308
|
+
await exportArchive(await writeAppStoreConnectExportOptions(exportOptionsDir));
|
|
2309
|
+
} finally {
|
|
2310
|
+
await removeTmpDir(exportOptionsDir);
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2217
2313
|
const ipaFile = fs.default.readdirSync(exportDir).find((file) => file.endsWith(".ipa"));
|
|
2218
2314
|
if (!ipaFile) throw new Error("IPA file not found after export");
|
|
2219
2315
|
return {
|
package/dist/index.d.cts
CHANGED
|
@@ -75,6 +75,10 @@ declare const enrichNativeBuildIosScheme: ({ scheme, hotUpdaterSchemeName }: {
|
|
|
75
75
|
* Builds a simulator `.app` for a `simulator` scheme, and otherwise archives
|
|
76
76
|
* and exports an `.ipa`, or returns the `.xcarchive` of a scheme it cannot
|
|
77
77
|
* export: one with neither `exportOptionsPlist` nor `signing.ascApiKey`.
|
|
78
|
+
*
|
|
79
|
+
* The artifact is in a temporary `buildDirectory`, which `dispose` removes
|
|
80
|
+
* once the caller has copied it out. A failed build removes it, and every
|
|
81
|
+
* other directory the build used, itself.
|
|
78
82
|
*/
|
|
79
83
|
declare const buildIos: ({ schemeConfig, minBundleId, credentials }: {
|
|
80
84
|
schemeConfig: EnrichedNativeBuildIosScheme;
|
|
@@ -92,6 +96,8 @@ declare const buildIos: ({ schemeConfig, minBundleId, credentials }: {
|
|
|
92
96
|
/** The app's `CFBundleVersion`. */
|
|
93
97
|
buildNumber: string | null;
|
|
94
98
|
};
|
|
99
|
+
/** Removes `buildDirectory`, once the artifact is copied out of it. */
|
|
100
|
+
dispose: () => Promise<void>;
|
|
95
101
|
}>;
|
|
96
102
|
//#endregion
|
|
97
103
|
//#region src/uploadToTestFlight.d.ts
|
package/dist/index.d.mts
CHANGED
|
@@ -76,6 +76,10 @@ declare const enrichNativeBuildIosScheme: ({ scheme, hotUpdaterSchemeName }: {
|
|
|
76
76
|
* Builds a simulator `.app` for a `simulator` scheme, and otherwise archives
|
|
77
77
|
* and exports an `.ipa`, or returns the `.xcarchive` of a scheme it cannot
|
|
78
78
|
* export: one with neither `exportOptionsPlist` nor `signing.ascApiKey`.
|
|
79
|
+
*
|
|
80
|
+
* The artifact is in a temporary `buildDirectory`, which `dispose` removes
|
|
81
|
+
* once the caller has copied it out. A failed build removes it, and every
|
|
82
|
+
* other directory the build used, itself.
|
|
79
83
|
*/
|
|
80
84
|
declare const buildIos: ({ schemeConfig, minBundleId, credentials }: {
|
|
81
85
|
schemeConfig: EnrichedNativeBuildIosScheme;
|
|
@@ -93,6 +97,8 @@ declare const buildIos: ({ schemeConfig, minBundleId, credentials }: {
|
|
|
93
97
|
/** The app's `CFBundleVersion`. */
|
|
94
98
|
buildNumber: string | null;
|
|
95
99
|
};
|
|
100
|
+
/** Removes `buildDirectory`, once the artifact is copied out of it. */
|
|
101
|
+
dispose: () => Promise<void>;
|
|
96
102
|
}>;
|
|
97
103
|
//#endregion
|
|
98
104
|
//#region src/uploadToTestFlight.d.ts
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
2
|
import { createReadStream, rmSync } from "node:fs";
|
|
3
|
-
import fs, { mkdtemp } from "node:fs/promises";
|
|
3
|
+
import fs, { mkdtemp, rm } from "node:fs/promises";
|
|
4
4
|
import net from "node:net";
|
|
5
5
|
import os, { tmpdir } from "node:os";
|
|
6
6
|
import path, { join } from "node:path";
|
|
@@ -122,7 +122,7 @@ var AscCommandError = class extends Error {
|
|
|
122
122
|
this.exitCode = exitCode;
|
|
123
123
|
}
|
|
124
124
|
};
|
|
125
|
-
const TERMINATION_SIGNALS$
|
|
125
|
+
const TERMINATION_SIGNALS$3 = [
|
|
126
126
|
"SIGHUP",
|
|
127
127
|
"SIGINT",
|
|
128
128
|
"SIGTERM"
|
|
@@ -146,10 +146,10 @@ const createWorkDirectory = async () => {
|
|
|
146
146
|
};
|
|
147
147
|
const stop = () => {
|
|
148
148
|
process.off("exit", remove);
|
|
149
|
-
for (const signal of TERMINATION_SIGNALS$
|
|
149
|
+
for (const signal of TERMINATION_SIGNALS$3) process.off(signal, onSignal);
|
|
150
150
|
};
|
|
151
151
|
process.on("exit", remove);
|
|
152
|
-
for (const signal of TERMINATION_SIGNALS$
|
|
152
|
+
for (const signal of TERMINATION_SIGNALS$3) process.on(signal, onSignal);
|
|
153
153
|
for (const directory of [
|
|
154
154
|
"home",
|
|
155
155
|
"session",
|
|
@@ -546,8 +546,55 @@ const resolvePodInstallPlan = ({ version, env }) => {
|
|
|
546
546
|
};
|
|
547
547
|
//#endregion
|
|
548
548
|
//#region src/utils/createRandomTmpDir.ts
|
|
549
|
+
const TERMINATION_SIGNALS$2 = [
|
|
550
|
+
"SIGHUP",
|
|
551
|
+
"SIGINT",
|
|
552
|
+
"SIGTERM"
|
|
553
|
+
];
|
|
554
|
+
const REMOVE_OPTIONS = {
|
|
555
|
+
force: true,
|
|
556
|
+
recursive: true,
|
|
557
|
+
maxRetries: 3
|
|
558
|
+
};
|
|
559
|
+
const liveDirectories = /* @__PURE__ */ new Set();
|
|
560
|
+
const onSignal = (signal) => {
|
|
561
|
+
removeLiveDirectories();
|
|
562
|
+
if (process.listenerCount(signal) === 0) process.kill(process.pid, signal);
|
|
563
|
+
};
|
|
564
|
+
const removeLiveDirectories = () => {
|
|
565
|
+
for (const directory of liveDirectories) try {
|
|
566
|
+
rmSync(directory, REMOVE_OPTIONS);
|
|
567
|
+
} catch {}
|
|
568
|
+
liveDirectories.clear();
|
|
569
|
+
stopListening();
|
|
570
|
+
};
|
|
571
|
+
const startListening = () => {
|
|
572
|
+
process.on("exit", removeLiveDirectories);
|
|
573
|
+
for (const signal of TERMINATION_SIGNALS$2) process.on(signal, onSignal);
|
|
574
|
+
};
|
|
575
|
+
const stopListening = () => {
|
|
576
|
+
process.off("exit", removeLiveDirectories);
|
|
577
|
+
for (const signal of TERMINATION_SIGNALS$2) process.off(signal, onSignal);
|
|
578
|
+
};
|
|
579
|
+
/**
|
|
580
|
+
* Creates a directory in the system's temporary directory, which
|
|
581
|
+
* `removeTmpDir` removes, and which is otherwise removed when the process
|
|
582
|
+
* exits or is stopped by a signal.
|
|
583
|
+
*/
|
|
549
584
|
const createRandomTmpDir = async (prefix = "apple-helper-") => {
|
|
550
|
-
|
|
585
|
+
const directory = await mkdtemp(join(tmpdir(), prefix));
|
|
586
|
+
if (liveDirectories.size === 0) startListening();
|
|
587
|
+
liveDirectories.add(directory);
|
|
588
|
+
return directory;
|
|
589
|
+
};
|
|
590
|
+
/**
|
|
591
|
+
* Removes a directory `createRandomTmpDir` created. It stays tracked until
|
|
592
|
+
* it is gone, so a signal during a removal that takes seconds, such as
|
|
593
|
+
* DerivedData's, still finishes it.
|
|
594
|
+
*/
|
|
595
|
+
const removeTmpDir = async (directory) => {
|
|
596
|
+
await rm(directory, REMOVE_OPTIONS);
|
|
597
|
+
if (liveDirectories.delete(directory) && liveDirectories.size === 0) stopListening();
|
|
551
598
|
};
|
|
552
599
|
//#endregion
|
|
553
600
|
//#region src/utils/platform.ts
|
|
@@ -851,53 +898,62 @@ const buildSettingsOverScheme = ({ minBundleId, authenticationArgs }) => ({
|
|
|
851
898
|
});
|
|
852
899
|
//#endregion
|
|
853
900
|
//#region src/builder/archiveXcodeProject.ts
|
|
854
|
-
|
|
901
|
+
/**
|
|
902
|
+
* Archives the scheme into `archiveDirectory`. The build's xcconfig is
|
|
903
|
+
* written to a temporary directory, removed whether the archive succeeds or
|
|
904
|
+
* not.
|
|
905
|
+
*/
|
|
906
|
+
const archiveXcodeProject = async ({ sourceDir, archiveDirectory, platform, installPods, destination, extraParams, configuration, xcodeScheme, xcconfig, logPrefix, minBundleId, authenticationArgs }) => {
|
|
855
907
|
if (installPods) await installPodsIfNeeded(sourceDir);
|
|
856
908
|
const xcodeProject = await parseXcodeProjectInfo(sourceDir);
|
|
857
|
-
const tmpDir = await createRandomTmpDir();
|
|
858
909
|
const archiveName = `${xcodeProject.name.replace(".xcworkspace", "").replace(".xcodeproj", "")}.xcarchive`;
|
|
859
|
-
const archivePath = path$1.join(
|
|
860
|
-
const
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
910
|
+
const archivePath = path$1.join(archiveDirectory, archiveName);
|
|
911
|
+
const tmpDir = await createRandomTmpDir();
|
|
912
|
+
try {
|
|
913
|
+
const build = await writeBuildXcconfig({
|
|
914
|
+
directory: tmpDir,
|
|
915
|
+
sourceDir,
|
|
916
|
+
xcconfig,
|
|
917
|
+
extraParams,
|
|
918
|
+
settings: buildSettingsOverScheme({
|
|
919
|
+
minBundleId,
|
|
920
|
+
authenticationArgs
|
|
921
|
+
})
|
|
922
|
+
});
|
|
923
|
+
const archiveArgs = prepareArchiveArgs({
|
|
924
|
+
authenticationArgs,
|
|
866
925
|
minBundleId,
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
extraParams: build.extraParams,
|
|
879
|
-
destination,
|
|
880
|
-
xcconfig: build.xcconfig,
|
|
881
|
-
xcodeScheme
|
|
882
|
-
});
|
|
883
|
-
p.log.info(`Xcode Archive Settings:
|
|
926
|
+
archivePath,
|
|
927
|
+
platform,
|
|
928
|
+
sourceDir,
|
|
929
|
+
xcodeProject,
|
|
930
|
+
configuration,
|
|
931
|
+
extraParams: build.extraParams,
|
|
932
|
+
destination,
|
|
933
|
+
xcconfig: build.xcconfig,
|
|
934
|
+
xcodeScheme
|
|
935
|
+
});
|
|
936
|
+
p.log.info(`Xcode Archive Settings:
|
|
884
937
|
Project ${xcodeProject.name}
|
|
885
938
|
Scheme ${xcodeScheme}
|
|
886
939
|
Platform ${platform}
|
|
887
940
|
Command xcodebuild ${archiveArgs.join(" ")}
|
|
888
941
|
`);
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
942
|
+
try {
|
|
943
|
+
await runXcodebuildWithLogging({
|
|
944
|
+
args: archiveArgs,
|
|
945
|
+
env: { HOT_UPDATER_MIN_BUNDLE_ID: minBundleId },
|
|
946
|
+
failureMessage: "Archive failed",
|
|
947
|
+
logPrefix,
|
|
948
|
+
sourceDir,
|
|
949
|
+
successMessage: "Archive completed successfully"
|
|
950
|
+
});
|
|
951
|
+
return { archivePath };
|
|
952
|
+
} catch (error) {
|
|
953
|
+
throw prettifyXcodebuildError(error);
|
|
954
|
+
}
|
|
955
|
+
} finally {
|
|
956
|
+
await removeTmpDir(tmpDir);
|
|
901
957
|
}
|
|
902
958
|
};
|
|
903
959
|
const prepareArchiveArgs = ({ xcodeScheme, archivePath, platform, sourceDir, xcodeProject, configuration = "Release", xcconfig, extraParams, destination = [], minBundleId, authenticationArgs }) => {
|
|
@@ -930,69 +986,83 @@ const prepareArchiveArgs = ({ xcodeScheme, archivePath, platform, sourceDir, xco
|
|
|
930
986
|
};
|
|
931
987
|
//#endregion
|
|
932
988
|
//#region src/builder/buildXcodeProject.ts
|
|
933
|
-
|
|
989
|
+
/**
|
|
990
|
+
* Builds the scheme in a temporary DerivedData directory, copies the built
|
|
991
|
+
* `.app` to `outputDirectory`, and removes DerivedData, which takes 10 GB or
|
|
992
|
+
* more, whether the build succeeds or not.
|
|
993
|
+
*/
|
|
994
|
+
const buildXcodeProject = async ({ sourceDir, outputDirectory, platform, xcodeScheme, configuration, deviceType, logPrefix, destination = [], useGenericDestination = false, installPods, extraParams, minBundleId, authenticationArgs }) => {
|
|
934
995
|
if (installPods) await installPodsIfNeeded(sourceDir);
|
|
935
996
|
const xcodeProject = await parseXcodeProjectInfo(sourceDir);
|
|
936
|
-
const
|
|
937
|
-
const resolvedDestinations = resolveDestinations({
|
|
938
|
-
destinations: destination,
|
|
939
|
-
useGeneric: useGenericDestination
|
|
940
|
-
});
|
|
941
|
-
if (resolvedDestinations.length === 0) resolvedDestinations.push(getDefaultDestination({
|
|
942
|
-
deviceType,
|
|
943
|
-
platform,
|
|
944
|
-
useGeneric: useGenericDestination
|
|
945
|
-
}));
|
|
946
|
-
const build = await writeBuildXcconfig({
|
|
947
|
-
directory: await createRandomTmpDir(),
|
|
948
|
-
sourceDir,
|
|
949
|
-
extraParams,
|
|
950
|
-
settings: buildSettingsOverScheme({
|
|
951
|
-
minBundleId,
|
|
952
|
-
authenticationArgs
|
|
953
|
-
})
|
|
954
|
-
});
|
|
955
|
-
const buildArgs = prepareBuildArgs({
|
|
956
|
-
authenticationArgs,
|
|
957
|
-
xcconfig: build.xcconfig,
|
|
958
|
-
minBundleId,
|
|
959
|
-
configuration,
|
|
960
|
-
derivedDataPath,
|
|
961
|
-
deviceType,
|
|
962
|
-
resolvedDestinations,
|
|
963
|
-
extraParams: build.extraParams,
|
|
964
|
-
platform,
|
|
965
|
-
xcodeScheme,
|
|
966
|
-
sourceDir,
|
|
967
|
-
xcodeProject
|
|
968
|
-
});
|
|
969
|
-
p.log.info(`Xcode Build Settings:
|
|
970
|
-
Project ${xcodeProject.name}
|
|
971
|
-
Scheme ${xcodeScheme}
|
|
972
|
-
Configuration ${configuration}
|
|
973
|
-
Platform ${platform}
|
|
974
|
-
Device Type ${deviceType}
|
|
975
|
-
Command xcodebuild ${buildArgs.join(" ")}
|
|
976
|
-
`);
|
|
997
|
+
const tmpDir = await createRandomTmpDir();
|
|
977
998
|
try {
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
999
|
+
const derivedDataPath = path$1.join(tmpDir, "DerivedData");
|
|
1000
|
+
const resolvedDestinations = resolveDestinations({
|
|
1001
|
+
destinations: destination,
|
|
1002
|
+
useGeneric: useGenericDestination
|
|
1003
|
+
});
|
|
1004
|
+
if (resolvedDestinations.length === 0) resolvedDestinations.push(getDefaultDestination({
|
|
1005
|
+
deviceType,
|
|
1006
|
+
platform,
|
|
1007
|
+
useGeneric: useGenericDestination
|
|
1008
|
+
}));
|
|
1009
|
+
const build = await writeBuildXcconfig({
|
|
1010
|
+
directory: tmpDir,
|
|
981
1011
|
sourceDir,
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
1012
|
+
extraParams,
|
|
1013
|
+
settings: buildSettingsOverScheme({
|
|
1014
|
+
minBundleId,
|
|
1015
|
+
authenticationArgs
|
|
1016
|
+
})
|
|
985
1017
|
});
|
|
986
|
-
|
|
1018
|
+
const buildArgs = prepareBuildArgs({
|
|
1019
|
+
authenticationArgs,
|
|
1020
|
+
xcconfig: build.xcconfig,
|
|
1021
|
+
minBundleId,
|
|
987
1022
|
configuration,
|
|
988
1023
|
derivedDataPath,
|
|
1024
|
+
deviceType,
|
|
989
1025
|
resolvedDestinations,
|
|
1026
|
+
extraParams: build.extraParams,
|
|
1027
|
+
platform,
|
|
990
1028
|
xcodeScheme,
|
|
991
1029
|
sourceDir,
|
|
992
1030
|
xcodeProject
|
|
993
1031
|
});
|
|
994
|
-
|
|
995
|
-
|
|
1032
|
+
p.log.info(`Xcode Build Settings:
|
|
1033
|
+
Project ${xcodeProject.name}
|
|
1034
|
+
Scheme ${xcodeScheme}
|
|
1035
|
+
Configuration ${configuration}
|
|
1036
|
+
Platform ${platform}
|
|
1037
|
+
Device Type ${deviceType}
|
|
1038
|
+
Command xcodebuild ${buildArgs.join(" ")}
|
|
1039
|
+
`);
|
|
1040
|
+
let builtAppPath;
|
|
1041
|
+
try {
|
|
1042
|
+
await runXcodebuildWithLogging({
|
|
1043
|
+
args: buildArgs,
|
|
1044
|
+
env: { HOT_UPDATER_MIN_BUNDLE_ID: minBundleId },
|
|
1045
|
+
sourceDir,
|
|
1046
|
+
logPrefix,
|
|
1047
|
+
successMessage: "Build completed successfully",
|
|
1048
|
+
failureMessage: "Build failed"
|
|
1049
|
+
});
|
|
1050
|
+
({appPath: builtAppPath} = await getBuildSettings({
|
|
1051
|
+
configuration,
|
|
1052
|
+
derivedDataPath,
|
|
1053
|
+
resolvedDestinations,
|
|
1054
|
+
xcodeScheme,
|
|
1055
|
+
sourceDir,
|
|
1056
|
+
xcodeProject
|
|
1057
|
+
}));
|
|
1058
|
+
} catch (error) {
|
|
1059
|
+
throw prettifyXcodebuildError(error);
|
|
1060
|
+
}
|
|
1061
|
+
const appPath = path$1.join(outputDirectory, path$1.basename(builtAppPath));
|
|
1062
|
+
await fs$1.promises.cp(builtAppPath, appPath, { recursive: true });
|
|
1063
|
+
return { appPath };
|
|
1064
|
+
} finally {
|
|
1065
|
+
await removeTmpDir(tmpDir);
|
|
996
1066
|
}
|
|
997
1067
|
};
|
|
998
1068
|
const prepareBuildArgs = ({ xcodeProject, sourceDir, platform, xcodeScheme, configuration, deviceType, resolvedDestinations, derivedDataPath, extraParams, minBundleId, authenticationArgs, xcconfig }) => {
|
|
@@ -1049,8 +1119,8 @@ const getBuildSettings = async ({ xcodeProject, sourceDir, xcodeScheme, configur
|
|
|
1049
1119
|
};
|
|
1050
1120
|
//#endregion
|
|
1051
1121
|
//#region src/builder/exportXcodeArchive.ts
|
|
1052
|
-
|
|
1053
|
-
|
|
1122
|
+
/** Exports the archive into `exportPath`. */
|
|
1123
|
+
const exportXcodeArchive = async ({ archivePath, exportPath, sourceDir, exportExtraParams, exportOptionsPlist, logPrefix, authenticationArgs }) => {
|
|
1054
1124
|
const exportArgs = prepareExportArgs({
|
|
1055
1125
|
authenticationArgs,
|
|
1056
1126
|
archivePath,
|
|
@@ -2080,21 +2150,41 @@ const readBuiltApp = async (appPath) => {
|
|
|
2080
2150
|
* Builds a simulator `.app` for a `simulator` scheme, and otherwise archives
|
|
2081
2151
|
* and exports an `.ipa`, or returns the `.xcarchive` of a scheme it cannot
|
|
2082
2152
|
* export: one with neither `exportOptionsPlist` nor `signing.ascApiKey`.
|
|
2153
|
+
*
|
|
2154
|
+
* The artifact is in a temporary `buildDirectory`, which `dispose` removes
|
|
2155
|
+
* once the caller has copied it out. A failed build removes it, and every
|
|
2156
|
+
* other directory the build used, itself.
|
|
2083
2157
|
*/
|
|
2084
2158
|
const buildIos = async ({ schemeConfig, minBundleId = createMinBundleId(), credentials }) => {
|
|
2085
2159
|
await assertXcodebuildExist();
|
|
2086
|
-
|
|
2160
|
+
if (schemeConfig.simulator && schemeConfig.destination.length) {
|
|
2161
|
+
p.log.error("The scheme option 'simulator' is not compatible with the 'destination' option.");
|
|
2162
|
+
process.exit(1);
|
|
2163
|
+
}
|
|
2087
2164
|
const buildDirectory = await createRandomTmpDir();
|
|
2088
|
-
|
|
2165
|
+
try {
|
|
2166
|
+
return {
|
|
2167
|
+
...await buildInto({
|
|
2168
|
+
schemeConfig,
|
|
2169
|
+
minBundleId,
|
|
2170
|
+
credentials,
|
|
2171
|
+
buildDirectory
|
|
2172
|
+
}),
|
|
2173
|
+
dispose: () => removeTmpDir(buildDirectory)
|
|
2174
|
+
};
|
|
2175
|
+
} catch (error) {
|
|
2176
|
+
await removeTmpDir(buildDirectory);
|
|
2177
|
+
throw error;
|
|
2178
|
+
}
|
|
2179
|
+
};
|
|
2180
|
+
const buildInto = async ({ schemeConfig, minBundleId, credentials, buildDirectory }) => {
|
|
2181
|
+
const iosProjectRoot = path$1.join(getCwd(), "ios");
|
|
2089
2182
|
if (schemeConfig.simulator) {
|
|
2090
|
-
if (schemeConfig.destination.length) {
|
|
2091
|
-
p.log.error("The scheme option 'simulator' is not compatible with the 'destination' option.");
|
|
2092
|
-
process.exit(1);
|
|
2093
|
-
}
|
|
2094
2183
|
const appDir = path$1.join(buildDirectory, "app");
|
|
2095
2184
|
await fs$1.promises.mkdir(appDir, { recursive: true });
|
|
2096
2185
|
const { appPath } = await buildXcodeProject({
|
|
2097
2186
|
sourceDir: iosProjectRoot,
|
|
2187
|
+
outputDirectory: appDir,
|
|
2098
2188
|
logPrefix: `ios-${schemeConfig.hotUpdaterSchemeName}-build`,
|
|
2099
2189
|
platform: schemeConfig.platform,
|
|
2100
2190
|
xcodeScheme: schemeConfig.scheme,
|
|
@@ -2105,13 +2195,11 @@ const buildIos = async ({ schemeConfig, minBundleId = createMinBundleId(), crede
|
|
|
2105
2195
|
useGenericDestination: true,
|
|
2106
2196
|
minBundleId
|
|
2107
2197
|
});
|
|
2108
|
-
const finalAppPath = path$1.join(appDir, path$1.basename(appPath));
|
|
2109
|
-
await fs$1.promises.cp(appPath, finalAppPath, { recursive: true });
|
|
2110
2198
|
p.log.success(`.app file created: ${path$1.basename(appPath)}`);
|
|
2111
2199
|
return {
|
|
2112
2200
|
buildDirectory,
|
|
2113
|
-
buildArtifactPath:
|
|
2114
|
-
builtApp: await readBuiltApp(
|
|
2201
|
+
buildArtifactPath: appPath,
|
|
2202
|
+
builtApp: await readBuiltApp(appPath)
|
|
2115
2203
|
};
|
|
2116
2204
|
} else {
|
|
2117
2205
|
const signing = await resolveXcodeSigning({
|
|
@@ -2145,7 +2233,9 @@ const archiveAndExport = async ({ schemeConfig, minBundleId, buildDirectory, aut
|
|
|
2145
2233
|
const iosProjectRoot = path$1.join(getCwd(), "ios");
|
|
2146
2234
|
const archiveDir = path$1.join(buildDirectory, "archive");
|
|
2147
2235
|
const exportDir = path$1.join(buildDirectory, "export");
|
|
2236
|
+
await fs$1.promises.mkdir(archiveDir, { recursive: true });
|
|
2148
2237
|
const { archivePath } = await archiveXcodeProject({
|
|
2238
|
+
archiveDirectory: archiveDir,
|
|
2149
2239
|
authenticationArgs,
|
|
2150
2240
|
minBundleId,
|
|
2151
2241
|
platform: schemeConfig.platform,
|
|
@@ -2158,9 +2248,7 @@ const archiveAndExport = async ({ schemeConfig, minBundleId, buildDirectory, aut
|
|
|
2158
2248
|
installPods: schemeConfig.installPods,
|
|
2159
2249
|
logPrefix: `ios-${schemeConfig.hotUpdaterSchemeName}-build-archive`
|
|
2160
2250
|
});
|
|
2161
|
-
const
|
|
2162
|
-
await fs$1.promises.cp(archivePath, finalArchivePath, { recursive: true });
|
|
2163
|
-
const appFromArchive = extractAppFromXcarchive(finalArchivePath);
|
|
2251
|
+
const appFromArchive = extractAppFromXcarchive(archivePath);
|
|
2164
2252
|
const archivedAppPath = appFromArchive ? path$1.join(archiveDir, path$1.basename(appFromArchive)) : void 0;
|
|
2165
2253
|
if (appFromArchive && archivedAppPath) {
|
|
2166
2254
|
await fs$1.promises.cp(appFromArchive, archivedAppPath, { recursive: true });
|
|
@@ -2168,20 +2256,28 @@ const archiveAndExport = async ({ schemeConfig, minBundleId, buildDirectory, aut
|
|
|
2168
2256
|
}
|
|
2169
2257
|
if (!schemeConfig.exportOptionsPlist && !authenticationArgs) return {
|
|
2170
2258
|
buildDirectory,
|
|
2171
|
-
buildArtifactPath:
|
|
2259
|
+
buildArtifactPath: archivePath,
|
|
2172
2260
|
builtApp: archivedAppPath ? await readBuiltApp(archivedAppPath) : void 0
|
|
2173
2261
|
};
|
|
2174
2262
|
await fs$1.promises.mkdir(exportDir, { recursive: true });
|
|
2175
|
-
const
|
|
2176
|
-
const { exportPath } = await exportXcodeArchive({
|
|
2263
|
+
const exportArchive = (exportOptionsPlist) => exportXcodeArchive({
|
|
2177
2264
|
archivePath,
|
|
2265
|
+
exportPath: exportDir,
|
|
2178
2266
|
authenticationArgs,
|
|
2179
2267
|
exportExtraParams: schemeConfig.exportExtraParams,
|
|
2180
2268
|
exportOptionsPlist,
|
|
2181
2269
|
sourceDir: iosProjectRoot,
|
|
2182
2270
|
logPrefix: `ios-${schemeConfig.hotUpdaterSchemeName}-build-export`
|
|
2183
2271
|
});
|
|
2184
|
-
|
|
2272
|
+
if (schemeConfig.exportOptionsPlist) await exportArchive(schemeConfig.exportOptionsPlist);
|
|
2273
|
+
else {
|
|
2274
|
+
const exportOptionsDir = await createRandomTmpDir();
|
|
2275
|
+
try {
|
|
2276
|
+
await exportArchive(await writeAppStoreConnectExportOptions(exportOptionsDir));
|
|
2277
|
+
} finally {
|
|
2278
|
+
await removeTmpDir(exportOptionsDir);
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2185
2281
|
const ipaFile = fs$1.readdirSync(exportDir).find((file) => file.endsWith(".ipa"));
|
|
2186
2282
|
if (!ipaFile) throw new Error("IPA file not found after export");
|
|
2187
2283
|
return {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/apple-helper",
|
|
3
|
-
"version": "1.2.0-rc.
|
|
3
|
+
"version": "1.2.0-rc.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.cjs",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"execa": "9.5.2",
|
|
31
31
|
"fast-xml-parser": "5.8.0",
|
|
32
|
-
"@hot-updater/cli-tools": "1.2.0-rc.
|
|
33
|
-
"@hot-updater/plugin-core": "1.2.0-rc.
|
|
32
|
+
"@hot-updater/cli-tools": "1.2.0-rc.2",
|
|
33
|
+
"@hot-updater/plugin-core": "1.2.0-rc.2"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/node": "^20"
|