nativescript 9.1.0-alpha.10 → 9.1.0-alpha.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/definitions/ios.d.ts
CHANGED
|
@@ -8,18 +8,18 @@ declare global {
|
|
|
8
8
|
setupSigningForDevice(
|
|
9
9
|
projectRoot: string,
|
|
10
10
|
projectData: IProjectData,
|
|
11
|
-
buildConfig: IOSBuildData
|
|
11
|
+
buildConfig: IOSBuildData,
|
|
12
12
|
): Promise<void>;
|
|
13
13
|
setupSigningFromTeam(
|
|
14
14
|
projectRoot: string,
|
|
15
15
|
projectData: IProjectData,
|
|
16
|
-
teamId: string
|
|
16
|
+
teamId: string,
|
|
17
17
|
): Promise<void>;
|
|
18
18
|
setupSigningFromProvision(
|
|
19
19
|
projectRoot: string,
|
|
20
20
|
projectData: IProjectData,
|
|
21
21
|
provision?: string,
|
|
22
|
-
mobileProvisionData?: any
|
|
22
|
+
mobileProvisionData?: any,
|
|
23
23
|
): Promise<void>;
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -27,17 +27,17 @@ declare global {
|
|
|
27
27
|
buildForSimulator(
|
|
28
28
|
platformData: IPlatformData,
|
|
29
29
|
projectData: IProjectData,
|
|
30
|
-
buildConfig: IBuildConfig
|
|
30
|
+
buildConfig: IBuildConfig,
|
|
31
31
|
): Promise<void>;
|
|
32
32
|
buildForDevice(
|
|
33
33
|
platformData: IPlatformData,
|
|
34
34
|
projectData: IProjectData,
|
|
35
|
-
buildConfig: IBuildConfig
|
|
35
|
+
buildConfig: IBuildConfig,
|
|
36
36
|
): Promise<string>;
|
|
37
37
|
buildForAppStore(
|
|
38
38
|
platformData: IPlatformData,
|
|
39
39
|
projectData: IProjectData,
|
|
40
|
-
buildConfig: IBuildConfig
|
|
40
|
+
buildConfig: IBuildConfig,
|
|
41
41
|
): Promise<string>;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -47,35 +47,44 @@ declare global {
|
|
|
47
47
|
applySPMPackages(
|
|
48
48
|
platformData: IPlatformData,
|
|
49
49
|
projectData: IProjectData,
|
|
50
|
-
pluginSpmPackages?: IosSPMPackage[]
|
|
50
|
+
pluginSpmPackages?: IosSPMPackage[],
|
|
51
51
|
);
|
|
52
52
|
getSPMPackages(
|
|
53
53
|
projectData: IProjectData,
|
|
54
|
-
platform: string
|
|
54
|
+
platform: string,
|
|
55
55
|
): IosSPMPackage[];
|
|
56
|
+
resolveSPMDependencies(
|
|
57
|
+
platformData: IPlatformData,
|
|
58
|
+
projectData: IProjectData,
|
|
59
|
+
options?: { showProgress?: boolean },
|
|
60
|
+
): Promise<void>;
|
|
61
|
+
ensureSPMDependenciesResolved(
|
|
62
|
+
platformData: IPlatformData,
|
|
63
|
+
projectData: IProjectData,
|
|
64
|
+
): Promise<void>;
|
|
56
65
|
}
|
|
57
66
|
|
|
58
67
|
interface IXcodebuildArgsService {
|
|
59
68
|
getBuildForSimulatorArgs(
|
|
60
69
|
platformData: IPlatformData,
|
|
61
70
|
projectData: IProjectData,
|
|
62
|
-
buildConfig: IBuildConfig
|
|
71
|
+
buildConfig: IBuildConfig,
|
|
63
72
|
): Promise<string[]>;
|
|
64
73
|
getBuildForDeviceArgs(
|
|
65
74
|
platformData: IPlatformData,
|
|
66
75
|
projectData: IProjectData,
|
|
67
|
-
buildConfig: IBuildConfig
|
|
76
|
+
buildConfig: IBuildConfig,
|
|
68
77
|
): Promise<string[]>;
|
|
69
78
|
getXcodeProjectArgs(
|
|
70
79
|
platformData: IPlatformData,
|
|
71
|
-
projectData: IProjectData
|
|
80
|
+
projectData: IProjectData,
|
|
72
81
|
): string[];
|
|
73
82
|
}
|
|
74
83
|
|
|
75
84
|
interface IXcodebuildCommandService {
|
|
76
85
|
executeCommand(
|
|
77
86
|
args: string[],
|
|
78
|
-
options: IXcodebuildCommandOptions
|
|
87
|
+
options: IXcodebuildCommandOptions,
|
|
79
88
|
): Promise<ISpawnResult>;
|
|
80
89
|
}
|
|
81
90
|
|
|
@@ -84,18 +93,24 @@ declare global {
|
|
|
84
93
|
cwd: string;
|
|
85
94
|
stdio?: string;
|
|
86
95
|
spawnOptions?: any;
|
|
96
|
+
/**
|
|
97
|
+
* When provided, xcodebuild's output is piped (rather than inherited) and
|
|
98
|
+
* forwarded here so the caller can render its own progress UI (e.g. a
|
|
99
|
+
* spinner for Swift Package resolution/download activity).
|
|
100
|
+
*/
|
|
101
|
+
onProgress?: (chunk: { data: string; pipe: string }) => void;
|
|
87
102
|
}
|
|
88
103
|
|
|
89
104
|
interface IExportOptionsPlistService {
|
|
90
105
|
createDevelopmentExportOptionsPlist(
|
|
91
106
|
archivePath: string,
|
|
92
107
|
projectData: IProjectData,
|
|
93
|
-
buildConfig: IBuildConfig
|
|
108
|
+
buildConfig: IBuildConfig,
|
|
94
109
|
): Promise<IExportOptionsPlistOutput>;
|
|
95
110
|
createDistributionExportOptionsPlist(
|
|
96
111
|
projectRoot: string,
|
|
97
112
|
projectData: IProjectData,
|
|
98
|
-
buildConfig: IBuildConfig
|
|
113
|
+
buildConfig: IBuildConfig,
|
|
99
114
|
): Promise<IExportOptionsPlistOutput>;
|
|
100
115
|
}
|
|
101
116
|
|
|
@@ -201,7 +201,10 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
|
|
|
201
201
|
};
|
|
202
202
|
}
|
|
203
203
|
async createProject(frameworkDir, frameworkVersion, projectData) {
|
|
204
|
-
|
|
204
|
+
var _a;
|
|
205
|
+
const packageName = ((_a = projectData.nsConfig.android) === null || _a === void 0 ? void 0 : _a.runtimePackageName) || constants.SCOPED_ANDROID_RUNTIME_NAME;
|
|
206
|
+
if (packageName === constants.SCOPED_ANDROID_RUNTIME_NAME &&
|
|
207
|
+
semver.lt(frameworkVersion, AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE)) {
|
|
205
208
|
this.$errors.fail(`The NativeScript CLI requires Android runtime ${AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE} or later to work properly.`);
|
|
206
209
|
}
|
|
207
210
|
this.$fs.ensureDirectoryExists(this.getPlatformData(projectData).projectRoot);
|
|
@@ -288,7 +291,10 @@ class AndroidProjectService extends projectServiceBaseLib.PlatformProjectService
|
|
|
288
291
|
return null;
|
|
289
292
|
}
|
|
290
293
|
async updatePlatform(currentVersion, newVersion, canUpdate, projectData, addPlatform, removePlatforms) {
|
|
291
|
-
|
|
294
|
+
var _a;
|
|
295
|
+
const packageName = ((_a = projectData.nsConfig.android) === null || _a === void 0 ? void 0 : _a.runtimePackageName) || constants.SCOPED_ANDROID_RUNTIME_NAME;
|
|
296
|
+
if (packageName === constants.SCOPED_ANDROID_RUNTIME_NAME &&
|
|
297
|
+
semver.eq(newVersion, AndroidProjectService.MIN_RUNTIME_VERSION_WITH_GRADLE)) {
|
|
292
298
|
const platformLowercase = this.getPlatformData(projectData).normalizedPlatformName.toLowerCase();
|
|
293
299
|
await removePlatforms([platformLowercase.split("@")[0]]);
|
|
294
300
|
await addPlatform(platformLowercase);
|
|
@@ -3,11 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.SPMService = void 0;
|
|
4
4
|
const yok_1 = require("../../common/yok");
|
|
5
5
|
const trapezedev_project_1 = require("@nstudio/trapezedev-project");
|
|
6
|
+
const color_1 = require("../../color");
|
|
6
7
|
const path = require("path");
|
|
7
8
|
class SPMService {
|
|
8
|
-
constructor($logger, $projectConfigService, $xcodebuildCommandService, $xcodebuildArgsService) {
|
|
9
|
+
constructor($logger, $fs, $projectConfigService, $terminalSpinnerService, $xcodebuildCommandService, $xcodebuildArgsService) {
|
|
9
10
|
this.$logger = $logger;
|
|
11
|
+
this.$fs = $fs;
|
|
10
12
|
this.$projectConfigService = $projectConfigService;
|
|
13
|
+
this.$terminalSpinnerService = $terminalSpinnerService;
|
|
11
14
|
this.$xcodebuildCommandService = $xcodebuildCommandService;
|
|
12
15
|
this.$xcodebuildArgsService = $xcodebuildArgsService;
|
|
13
16
|
}
|
|
@@ -24,7 +27,7 @@ class SPMService {
|
|
|
24
27
|
mergePluginSPMPackages(appPackages, pluginPackages) {
|
|
25
28
|
// include swift packages from plugin configs
|
|
26
29
|
// but allow app packages to override plugin packages with the same name
|
|
27
|
-
const appPackageNames = new Set(appPackages.map(pkg => pkg.name));
|
|
30
|
+
const appPackageNames = new Set(appPackages.map((pkg) => pkg.name));
|
|
28
31
|
for (const pluginPkg of pluginPackages) {
|
|
29
32
|
if (appPackageNames.has(pluginPkg.name)) {
|
|
30
33
|
this.$logger.trace(`SPM: app package overrides plugin package: ${pluginPkg.name}`);
|
|
@@ -39,7 +42,7 @@ class SPMService {
|
|
|
39
42
|
// return this.getSPMPackages(projectData).length > 0;
|
|
40
43
|
// }
|
|
41
44
|
async applySPMPackages(platformData, projectData, pluginSpmPackages) {
|
|
42
|
-
var _a;
|
|
45
|
+
var _a, _b;
|
|
43
46
|
try {
|
|
44
47
|
const spmPackages = this.getSPMPackages(projectData, platformData.platformNameLowerCase);
|
|
45
48
|
if (pluginSpmPackages === null || pluginSpmPackages === void 0 ? void 0 : pluginSpmPackages.length) {
|
|
@@ -79,23 +82,199 @@ class SPMService {
|
|
|
79
82
|
}
|
|
80
83
|
await project.commit();
|
|
81
84
|
// finally resolve the dependencies
|
|
82
|
-
await this.resolveSPMDependencies(platformData, projectData
|
|
85
|
+
await this.resolveSPMDependencies(platformData, projectData, {
|
|
86
|
+
showProgress: true,
|
|
87
|
+
});
|
|
83
88
|
}
|
|
84
89
|
catch (err) {
|
|
90
|
+
// best-effort, but don't bury the failure below trace level — a red
|
|
91
|
+
// resolve spinner with no visible reason is confusing. Warn with the
|
|
92
|
+
// message, keep the full error at trace.
|
|
93
|
+
this.$logger.warn(`Failed to apply Swift Package dependencies: ${(_b = err === null || err === void 0 ? void 0 : err.message) !== null && _b !== void 0 ? _b : err}`);
|
|
85
94
|
this.$logger.trace("SPM: error applying SPM packages: ", err);
|
|
86
95
|
}
|
|
87
96
|
}
|
|
88
|
-
|
|
89
|
-
|
|
97
|
+
/**
|
|
98
|
+
* Resolves (downloads + pins) the Swift Package dependencies referenced by
|
|
99
|
+
* the Xcode project. On a first build this is where the NativeScript runtime
|
|
100
|
+
* (now distributed as a remote Swift package) and any other SPM packages are
|
|
101
|
+
* actually downloaded — which can take a while. Pass `showProgress` to render
|
|
102
|
+
* a live spinner so the CLI doesn't look stalled while that happens.
|
|
103
|
+
*
|
|
104
|
+
* In verbose mode (`--log trace`) the condensed spinner is bypassed and
|
|
105
|
+
* xcodebuild's raw resolution log is streamed straight through instead.
|
|
106
|
+
*/
|
|
107
|
+
async resolveSPMDependencies(platformData, projectData, options) {
|
|
108
|
+
const args = this.$xcodebuildArgsService
|
|
90
109
|
.getXcodeProjectArgs(platformData, projectData)
|
|
91
110
|
.concat([
|
|
92
111
|
"-destination",
|
|
93
112
|
"generic/platform=iOS",
|
|
94
113
|
"-resolvePackageDependencies",
|
|
95
|
-
])
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
114
|
+
]);
|
|
115
|
+
// Without progress, or when verbose: let xcodebuild's own resolution log
|
|
116
|
+
// stream straight to the terminal (inherited stdio). Verbose users want
|
|
117
|
+
// the raw log, not a condensed spinner that hides it.
|
|
118
|
+
if (!(options === null || options === void 0 ? void 0 : options.showProgress) || this.$logger.isVerbose()) {
|
|
119
|
+
await this.$xcodebuildCommandService.executeCommand(args, {
|
|
120
|
+
cwd: projectData.projectDir,
|
|
121
|
+
message: "Resolving Swift Package dependencies...",
|
|
122
|
+
});
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
const spinner = this.$terminalSpinnerService.createSpinner();
|
|
126
|
+
const startedAt = Date.now();
|
|
127
|
+
let activity = "Resolving Swift Package dependencies";
|
|
128
|
+
let lineBuffer = "";
|
|
129
|
+
const render = () => {
|
|
130
|
+
const elapsed = Math.round((Date.now() - startedAt) / 1000);
|
|
131
|
+
spinner.text = `${activity}… ${color_1.color.dim(`(${this.formatElapsed(elapsed)})`)}`;
|
|
132
|
+
};
|
|
133
|
+
// keep the elapsed timer ticking even when xcodebuild is silent (e.g.
|
|
134
|
+
// while a binary artifact downloads) so the user can see it's alive.
|
|
135
|
+
const ticker = setInterval(render, 1000);
|
|
136
|
+
const onProgress = (chunk) => {
|
|
137
|
+
lineBuffer += chunk.data;
|
|
138
|
+
const lines = lineBuffer.split("\n");
|
|
139
|
+
// keep the last (possibly partial) line in the buffer
|
|
140
|
+
lineBuffer = lines.pop();
|
|
141
|
+
for (const line of lines) {
|
|
142
|
+
const described = this.describeSPMActivity(line);
|
|
143
|
+
if (described) {
|
|
144
|
+
activity = described;
|
|
145
|
+
render();
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
render();
|
|
150
|
+
spinner.start();
|
|
151
|
+
try {
|
|
152
|
+
await this.$xcodebuildCommandService.executeCommand(args, {
|
|
153
|
+
cwd: projectData.projectDir,
|
|
154
|
+
onProgress,
|
|
155
|
+
});
|
|
156
|
+
spinner.succeed(color_1.color.green("Swift Package dependencies resolved"));
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
spinner.fail(color_1.color.red("Failed to resolve Swift Package dependencies"));
|
|
160
|
+
throw err;
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
clearInterval(ticker);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Best-effort pre-resolve before a build so the (potentially slow) first-time
|
|
168
|
+
* Swift package download happens under a clear progress indicator instead of
|
|
169
|
+
* silently inside the subsequent "Xcode build..." step. No-op when the
|
|
170
|
+
* project has no SPM references or they're already resolved.
|
|
171
|
+
*/
|
|
172
|
+
async ensureSPMDependenciesResolved(platformData, projectData) {
|
|
173
|
+
if (!this.hasSPMReferences(platformData, projectData)) {
|
|
174
|
+
this.$logger.trace("SPM: project has no Swift Package references.");
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
if (this.arePackagesResolved(platformData, projectData)) {
|
|
178
|
+
this.$logger.trace("SPM: Swift Package dependencies already resolved; skipping pre-resolve.");
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
try {
|
|
182
|
+
await this.resolveSPMDependencies(platformData, projectData, {
|
|
183
|
+
showProgress: true,
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
catch (err) {
|
|
187
|
+
// non-fatal: the build itself will resolve packages and surface the
|
|
188
|
+
// authoritative error if something is genuinely wrong.
|
|
189
|
+
this.$logger.trace("SPM: pre-resolve failed (continuing): ", err);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Maps a raw xcodebuild/SwiftPM resolution log line to a concise,
|
|
194
|
+
* user-facing activity description (or null for lines we don't surface).
|
|
195
|
+
*/
|
|
196
|
+
describeSPMActivity(line) {
|
|
197
|
+
const trimmed = line.trim();
|
|
198
|
+
if (!trimmed) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
// the big, otherwise-silent wait on a first build: a binary artifact
|
|
202
|
+
// (the NativeScript runtime xcframework) downloading.
|
|
203
|
+
if (/Downloading binary artifact/i.test(trimmed)) {
|
|
204
|
+
if (/ios-spm|nativescript/i.test(trimmed)) {
|
|
205
|
+
return "Downloading the NativeScript runtime (first build only)";
|
|
206
|
+
}
|
|
207
|
+
return "Downloading Swift Package binaries (first build only)";
|
|
208
|
+
}
|
|
209
|
+
if (/^Fetching\b/i.test(trimmed)) {
|
|
210
|
+
return this.describePackageActivity("Fetching", trimmed);
|
|
211
|
+
}
|
|
212
|
+
if (/^Cloning\b/i.test(trimmed)) {
|
|
213
|
+
return this.describePackageActivity("Cloning", trimmed);
|
|
214
|
+
}
|
|
215
|
+
if (/Computing version for/i.test(trimmed)) {
|
|
216
|
+
return "Computing package versions";
|
|
217
|
+
}
|
|
218
|
+
if (/Resolve Package Graph/i.test(trimmed)) {
|
|
219
|
+
return "Resolving Swift Package graph";
|
|
220
|
+
}
|
|
221
|
+
if (/Resolved source packages/i.test(trimmed)) {
|
|
222
|
+
return "Finalizing Swift Package dependencies";
|
|
223
|
+
}
|
|
224
|
+
return null;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Builds a stable, self-explanatory activity label with the package being
|
|
228
|
+
* worked on in parentheses, e.g. "Fetching Swift Packages (Auth0.swift)".
|
|
229
|
+
*/
|
|
230
|
+
describePackageActivity(verb, line) {
|
|
231
|
+
const packageRef = this.shortenPackageRef(line);
|
|
232
|
+
return packageRef
|
|
233
|
+
? `${verb} Swift Packages (${packageRef})`
|
|
234
|
+
: `${verb} Swift Packages`;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Extracts a short, readable name from a SwiftPM repo URL/log line, or null
|
|
238
|
+
* when the line contains no URL to name the package by.
|
|
239
|
+
*/
|
|
240
|
+
shortenPackageRef(line) {
|
|
241
|
+
const match = line.match(/https?:\/\/\S+/);
|
|
242
|
+
if (!match) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
245
|
+
return path
|
|
246
|
+
.basename(match[0])
|
|
247
|
+
.replace(/\.git$/, "")
|
|
248
|
+
.replace(/[)\s].*$/, "");
|
|
249
|
+
}
|
|
250
|
+
/** Formats an elapsed duration in whole seconds as "5m 15s". */
|
|
251
|
+
formatElapsed(totalSeconds) {
|
|
252
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
253
|
+
const seconds = totalSeconds % 60;
|
|
254
|
+
return `${minutes}m ${seconds}s`;
|
|
255
|
+
}
|
|
256
|
+
/** True when the Xcode project references any Swift packages. */
|
|
257
|
+
hasSPMReferences(platformData, projectData) {
|
|
258
|
+
const pbxprojPath = path.join(platformData.projectRoot, `${projectData.projectName}.xcodeproj`, "project.pbxproj");
|
|
259
|
+
if (!this.$fs.exists(pbxprojPath)) {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
const contents = this.$fs.readText(pbxprojPath);
|
|
263
|
+
return (contents.includes("XCRemoteSwiftPackageReference") ||
|
|
264
|
+
contents.includes("XCLocalSwiftPackageReference") ||
|
|
265
|
+
contents.includes("packageReferences"));
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* True when a Package.resolved already exists for the project — i.e. packages
|
|
269
|
+
* have been resolved at least once, so the build's own resolve step will be a
|
|
270
|
+
* fast no-op rather than a slow, silent first-time download.
|
|
271
|
+
*/
|
|
272
|
+
arePackagesResolved(platformData, projectData) {
|
|
273
|
+
const candidates = [
|
|
274
|
+
path.join(platformData.projectRoot, `${projectData.projectName}.xcworkspace`, "xcshareddata", "swiftpm", "Package.resolved"),
|
|
275
|
+
path.join(platformData.projectRoot, `${projectData.projectName}.xcodeproj`, "project.xcworkspace", "xcshareddata", "swiftpm", "Package.resolved"),
|
|
276
|
+
];
|
|
277
|
+
return candidates.some((p) => this.$fs.exists(p));
|
|
99
278
|
}
|
|
100
279
|
}
|
|
101
280
|
exports.SPMService = SPMService;
|
|
@@ -10,9 +10,22 @@ class XcodebuildCommandService {
|
|
|
10
10
|
this.$logger = $logger;
|
|
11
11
|
}
|
|
12
12
|
async executeCommand(args, options) {
|
|
13
|
-
const { message, cwd, stdio, spawnOptions } = options;
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const { message, cwd, stdio, spawnOptions, onProgress } = options;
|
|
14
|
+
// A caller rendering its own progress UI owns stdout, so skip the
|
|
15
|
+
// default "Xcode build..." line that would otherwise clobber it.
|
|
16
|
+
if (!onProgress) {
|
|
17
|
+
this.$logger.info(message || "Xcode build...");
|
|
18
|
+
}
|
|
19
|
+
const childProcessOptions = {
|
|
20
|
+
cwd,
|
|
21
|
+
stdio: onProgress ? "pipe" : stdio || "inherit",
|
|
22
|
+
};
|
|
23
|
+
let detachProgress;
|
|
24
|
+
if (onProgress) {
|
|
25
|
+
const handler = (chunk) => onProgress(chunk);
|
|
26
|
+
this.$childProcess.on(constants.BUILD_OUTPUT_EVENT_NAME, handler);
|
|
27
|
+
detachProgress = () => this.$childProcess.removeListener(constants.BUILD_OUTPUT_EVENT_NAME, handler);
|
|
28
|
+
}
|
|
16
29
|
try {
|
|
17
30
|
const commandResult = await this.$childProcess.spawnFromEvent("xcodebuild", args, "exit", childProcessOptions, spawnOptions || {
|
|
18
31
|
emitOptions: { eventName: constants.BUILD_OUTPUT_EVENT_NAME },
|
|
@@ -23,6 +36,9 @@ class XcodebuildCommandService {
|
|
|
23
36
|
catch (err) {
|
|
24
37
|
this.$errors.fail(err.message);
|
|
25
38
|
}
|
|
39
|
+
finally {
|
|
40
|
+
detachProgress === null || detachProgress === void 0 ? void 0 : detachProgress();
|
|
41
|
+
}
|
|
26
42
|
}
|
|
27
43
|
}
|
|
28
44
|
exports.XcodebuildCommandService = XcodebuildCommandService;
|
|
@@ -243,6 +243,10 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
243
243
|
}
|
|
244
244
|
async buildProject(projectRoot, projectData, buildData) {
|
|
245
245
|
const platformData = this.getPlatformData(projectData);
|
|
246
|
+
// On a first build, the runtime (and any other Swift packages) download
|
|
247
|
+
// here. Pre-resolve under a clear spinner so the subsequent
|
|
248
|
+
// "Xcode build..." step doesn't appear to hang while that happens.
|
|
249
|
+
await this.$spmService.ensureSPMDependenciesResolved(platformData, projectData);
|
|
246
250
|
const handler = (data) => {
|
|
247
251
|
this.emit(constants.BUILD_OUTPUT_EVENT_NAME, data);
|
|
248
252
|
};
|
|
@@ -356,7 +360,18 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
356
360
|
project.addFramework(relativeStaticLibPath);
|
|
357
361
|
const relativeHeaderSearchPath = path.join(this.getLibSubpathRelativeToProjectPath(headersSubpath, projectData));
|
|
358
362
|
project.addToHeaderSearchPaths({ relativePath: relativeHeaderSearchPath });
|
|
359
|
-
|
|
363
|
+
// Write the generated modulemap into a CLI-managed folder under the
|
|
364
|
+
// platform root (never into node_modules). The modulemap references the
|
|
365
|
+
// plugin's headers in-place via relative paths, so nothing is copied.
|
|
366
|
+
const modulemapDir = path.join(this.getPlatformData(projectData).projectRoot, IOSProjectService.GENERATED_PLUGINS_DIR_NAME, libraryName);
|
|
367
|
+
const hasModulemap = this.generateModulemap(headersSubpath, libraryName, modulemapDir);
|
|
368
|
+
if (hasModulemap) {
|
|
369
|
+
// Put the modulemap dir on the header search path so clang discovers
|
|
370
|
+
// the module there instead of inside node_modules.
|
|
371
|
+
project.addToHeaderSearchPaths({
|
|
372
|
+
relativePath: this.getLibSubpathRelativeToProjectPath(modulemapDir, projectData),
|
|
373
|
+
});
|
|
374
|
+
}
|
|
360
375
|
this.savePbxProj(project, projectData);
|
|
361
376
|
}
|
|
362
377
|
async prepareProject(projectData, prepareData) {
|
|
@@ -905,23 +920,46 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
905
920
|
project.removeFromHeaderSearchPaths({
|
|
906
921
|
relativePath: relativeHeaderSearchPath,
|
|
907
922
|
});
|
|
923
|
+
// Remove the generated modulemap dir search path (see addStaticLibrary)
|
|
924
|
+
const modulemapDir = path.join(this.getPlatformData(projectData).projectRoot, IOSProjectService.GENERATED_PLUGINS_DIR_NAME, path.basename(staticLibPath, ".a"));
|
|
925
|
+
project.removeFromHeaderSearchPaths({
|
|
926
|
+
relativePath: this.getLibSubpathRelativeToProjectPath(modulemapDir, projectData),
|
|
927
|
+
});
|
|
908
928
|
});
|
|
909
929
|
this.savePbxProj(project, projectData);
|
|
910
930
|
}
|
|
911
|
-
generateModulemap(headersFolderPath, libraryName) {
|
|
931
|
+
generateModulemap(headersFolderPath, libraryName, modulemapDir) {
|
|
932
|
+
const modulemapPath = path.join(modulemapDir, "module.modulemap");
|
|
933
|
+
// A plugin may ship a `.a` without an `include/{lib}` headers folder. In
|
|
934
|
+
// that case there's nothing to expose as a module - clean up any stale
|
|
935
|
+
// modulemap and bail out instead of letting readDirectory throw.
|
|
936
|
+
if (!this.$fs.exists(headersFolderPath)) {
|
|
937
|
+
if (this.$fs.exists(modulemapPath)) {
|
|
938
|
+
this.$fs.deleteFile(modulemapPath);
|
|
939
|
+
}
|
|
940
|
+
return false;
|
|
941
|
+
}
|
|
912
942
|
const headersFilter = (fileName, containingFolderPath) => path.extname(fileName) === ".h" &&
|
|
913
943
|
this.$fs.getFsStats(path.join(containingFolderPath, fileName)).isFile();
|
|
914
944
|
const headersFolderContents = this.$fs.readDirectory(headersFolderPath);
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
.
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
return;
|
|
945
|
+
const headerFiles = headersFolderContents.filter((item) => headersFilter(item, headersFolderPath));
|
|
946
|
+
if (!headerFiles.length) {
|
|
947
|
+
if (this.$fs.exists(modulemapPath)) {
|
|
948
|
+
this.$fs.deleteFile(modulemapPath);
|
|
949
|
+
}
|
|
950
|
+
return false;
|
|
921
951
|
}
|
|
922
|
-
|
|
952
|
+
// Reference the plugin's headers (still in node_modules) relative to the
|
|
953
|
+
// generated modulemap's location, so we don't copy headers or write into
|
|
954
|
+
// node_modules.
|
|
955
|
+
const headers = _.map(headerFiles, (value) => {
|
|
956
|
+
const relativeHeaderPath = path.relative(modulemapDir, path.join(headersFolderPath, value));
|
|
957
|
+
return `header "${relativeHeaderPath}"`;
|
|
958
|
+
});
|
|
923
959
|
const modulemap = `module ${libraryName} { explicit module ${libraryName} { ${headers.join(" ")} } }`;
|
|
924
|
-
this.$fs.
|
|
960
|
+
this.$fs.ensureDirectoryExists(modulemapDir);
|
|
961
|
+
this.$fs.writeFile(modulemapPath, modulemap);
|
|
962
|
+
return true;
|
|
925
963
|
}
|
|
926
964
|
async mergeProjectXcconfigFiles(projectData) {
|
|
927
965
|
const platformData = this.getPlatformData(projectData);
|
|
@@ -995,6 +1033,9 @@ class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase
|
|
|
995
1033
|
exports.IOSProjectService = IOSProjectService;
|
|
996
1034
|
IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER = "__PROJECT_NAME__";
|
|
997
1035
|
IOSProjectService.IOS_PLATFORM_NAME = "ios";
|
|
1036
|
+
// CLI-managed folder under the platform root where we write generated
|
|
1037
|
+
// artifacts (e.g. plugin modulemaps) so we never write into node_modules
|
|
1038
|
+
IOSProjectService.GENERATED_PLUGINS_DIR_NAME = ".plugins";
|
|
998
1039
|
__decorate([
|
|
999
1040
|
(0, helpers_2.hook)("buildIOS")
|
|
1000
1041
|
], IOSProjectService.prototype, "buildProject", null);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nativescript",
|
|
3
3
|
"main": "./lib/nativescript-cli-lib.js",
|
|
4
|
-
"version": "9.1.0-alpha.
|
|
4
|
+
"version": "9.1.0-alpha.12",
|
|
5
5
|
"author": "NativeScript <oss@nativescript.org>",
|
|
6
6
|
"description": "Command-line interface for building NativeScript projects",
|
|
7
7
|
"bin": {
|