-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Expand file tree
/
Copy pathspm.ts
More file actions
223 lines (185 loc) · 7.77 KB
/
spm.ts
File metadata and controls
223 lines (185 loc) · 7.77 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import { pathExists, existsSync, readFileSync, writeFileSync, remove, move, mkdtemp } from 'fs-extra';
import { tmpdir } from 'os';
import { join, relative, resolve } from 'path';
import type { PlistObject } from 'plist';
import { build, parse } from 'plist';
import { extract } from 'tar';
import { getCapacitorPackageVersion } from '../common';
import type { Config } from '../definitions';
import { fatal } from '../errors';
import { getMajoriOSVersion } from '../ios/common';
import { logger } from '../log';
import type { Plugin } from '../plugin';
import { getPluginType, PluginType } from '../plugin';
import { runCommand } from '../util/subprocess';
export interface SwiftPlugin {
name: string;
path: string;
}
/**
* @deprecated use config.ios.packageManager
* @param config
* @returns 'Cocoapods' | 'SPM'
*/
export async function checkPackageManager(config: Config): Promise<'Cocoapods' | 'SPM'> {
const iosDirectory = config.ios.nativeProjectDirAbs;
if (existsSync(resolve(iosDirectory, 'CapApp-SPM'))) {
return 'SPM';
}
return 'Cocoapods';
}
export async function findPackageSwiftFile(config: Config): Promise<string> {
const packageDirectory = resolve(config.ios.nativeProjectDirAbs, 'CapApp-SPM');
return resolve(packageDirectory, 'Package.swift');
}
export async function generatePackageFile(config: Config, plugins: Plugin[]): Promise<void> {
const packageSwiftFile = await findPackageSwiftFile(config);
try {
logger.info('Writing Package.swift');
const textToWrite = await generatePackageText(config, plugins);
writeFileSync(packageSwiftFile, textToWrite);
} catch (err) {
logger.error(`Unable to write to ${packageSwiftFile}. Verify it is not already open. \n Error: ${err}`);
}
}
export async function checkPluginsForPackageSwift(config: Config, plugins: Plugin[]): Promise<Plugin[]> {
const iOSCapacitorPlugins = plugins.filter((p) => getPluginType(p, 'ios') === PluginType.Core);
const packageSwiftPluginList = await pluginsWithPackageSwift(iOSCapacitorPlugins);
if (plugins.length == packageSwiftPluginList.length) {
logger.debug(`Found ${plugins.length} iOS plugins, ${packageSwiftPluginList.length} have a Package.swift file`);
logger.info('All plugins have a Package.swift file and will be included in Package.swift');
} else {
logger.warn('Some installed packages are not compatable with SPM');
}
return packageSwiftPluginList;
}
export async function extractSPMPackageDirectory(config: Config): Promise<void> {
const spmDirectory = join(config.ios.nativeProjectDirAbs, 'CapApp-SPM');
const spmTemplate = join(config.cli.assetsDirAbs, 'ios-spm-template.tar.gz');
const debugConfig = join(config.ios.platformDirAbs, 'debug.xcconfig');
logger.info('Extracting ' + spmTemplate + ' to ' + spmDirectory);
try {
const tempCapDir = await mkdtemp(join(tmpdir(), 'cap-'));
const tempCapSPM = join(tempCapDir, 'App', 'CapApp-SPM');
const tempDebugXCConfig = join(tempCapDir, 'debug.xcconfig');
await extract({ file: spmTemplate, cwd: tempCapDir });
await move(tempCapSPM, spmDirectory);
await move(tempDebugXCConfig, debugConfig);
} catch (err) {
fatal('Failed to create ' + spmDirectory + ' with error: ' + err);
}
}
export async function removeCocoapodsFiles(config: Config): Promise<void> {
const iosDirectory = config.ios.nativeProjectDirAbs;
const podFile = resolve(iosDirectory, 'Podfile');
const podlockFile = resolve(iosDirectory, 'Podfile.lock');
const xcworkspaceFile = resolve(iosDirectory, 'App.xcworkspace');
await remove(podFile);
await remove(podlockFile);
await remove(xcworkspaceFile);
}
export async function generatePackageText(config: Config, plugins: Plugin[]): Promise<string> {
const iosPlatformVersion = await getCapacitorPackageVersion(config, config.ios.name);
const iosVersion = getMajoriOSVersion(config);
const swiftToolsVersion = config.app.extConfig.experimental?.ios?.spm?.swiftToolsVersion ?? '5.9';
let packageSwiftText = `// swift-tools-version: ${swiftToolsVersion}
import PackageDescription
// DO NOT MODIFY THIS FILE - managed by Capacitor CLI commands
let package = Package(
name: "CapApp-SPM",
platforms: [.iOS(.v${iosVersion})],
products: [
.library(
name: "CapApp-SPM",
targets: ["CapApp-SPM"])
],
dependencies: [
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", exact: "${iosPlatformVersion}")`;
for (const plugin of plugins) {
if (getPluginType(plugin, config.ios.name) === PluginType.Cordova) {
packageSwiftText += `,\n .package(name: "${plugin.name}", path: "../../capacitor-cordova-ios-plugins/sources/${plugin.name}")`;
} else {
const relPath = relative(config.ios.nativeXcodeProjDirAbs, plugin.rootPath);
packageSwiftText += `,\n .package(name: "${plugin.ios?.name}", path: "${relPath}")`;
}
}
packageSwiftText += `
],
targets: [
.target(
name: "CapApp-SPM",
dependencies: [
.product(name: "Capacitor", package: "capacitor-swift-pm"),
.product(name: "Cordova", package: "capacitor-swift-pm")`;
for (const plugin of plugins) {
packageSwiftText += `,\n .product(name: "${plugin.ios?.name}", package: "${plugin.ios?.name}")`;
}
packageSwiftText += `
]
)
]
)
`;
return packageSwiftText;
}
export async function runCocoapodsDeintegrate(config: Config): Promise<void> {
const podPath = await config.ios.podPath;
const projectFileName = config.ios.nativeXcodeProjDirAbs;
const useBundler = (await config.ios.packageManager) === 'bundler';
logger.info('Running pod deintegrate on project ' + projectFileName);
if (useBundler) {
logger.info('Found bundler, using it to run CocoaPods.');
await runCommand('bundle', ['exec', 'pod', 'deintegrate', projectFileName], {
cwd: config.ios.nativeProjectDirAbs,
});
} else {
await runCommand(podPath, ['deintegrate', projectFileName], {
cwd: config.ios.nativeProjectDirAbs,
});
}
}
export async function addInfoPlistDebugIfNeeded(config: Config): Promise<void> {
type Mutable<T> = { -readonly [P in keyof T]: T[P] };
const infoPlist = resolve(config.ios.nativeTargetDirAbs, 'Info.plist');
logger.info('Checking ' + infoPlist + ' for CAPACITOR_DEBUG');
if (existsSync(infoPlist)) {
const infoPlistContents = readFileSync(infoPlist, 'utf-8');
const plistEntries = parse(infoPlistContents) as Mutable<PlistObject>;
if (plistEntries['CAPACITOR_DEBUG'] === undefined) {
logger.info('Writing CAPACITOR_DEBUG to ' + infoPlist);
plistEntries['CAPACITOR_DEBUG'] = '$(CAPACITOR_DEBUG)';
const plistToWrite = build(plistEntries);
writeFileSync(infoPlist, plistToWrite);
} else {
logger.warn('Found CAPACITOR_DEBUG set to ' + plistEntries['CAPACITOR_DEBUG'] + ', skipping.');
}
} else {
logger.warn(infoPlist + ' not found.');
}
}
export async function checkSwiftToolsVersion(config: Config, version: string | undefined): Promise<string | null> {
if (!version) {
return null;
}
const swiftToolsVersionRegex = /^[0-9]+\.[0-9]+(\.[0-9]+)?$/;
if (!swiftToolsVersionRegex.test(version)) {
return (
`Invalid Swift tools version: "${version}".\n` +
`The Swift tools version must be in major.minor or major.minor.patch format (e.g., "5.9", "6.0", "5.9.2").`
);
}
return null;
}
// Private Functions
async function pluginsWithPackageSwift(plugins: Plugin[]): Promise<Plugin[]> {
const pluginList: Plugin[] = [];
for (const plugin of plugins) {
const packageSwiftFound = await pathExists(join(plugin.rootPath, 'Package.swift'));
if (packageSwiftFound) {
pluginList.push(plugin);
} else {
logger.warn(plugin.id + ' does not have a Package.swift');
}
}
return pluginList;
}