UNPKG

12.9 kBJavaScriptView Raw
1"use strict";
2var __importDefault = (this && this.__importDefault) || function (mod) {
3 return (mod && mod.__esModule) ? mod : { "default": mod };
4};
5Object.defineProperty(exports, "__esModule", { value: true });
6exports.CocoaPodsPackageManager = exports.extractMissingDependencyError = exports.CocoaPodsError = void 0;
7const spawn_async_1 = __importDefault(require("@expo/spawn-async"));
8const chalk_1 = __importDefault(require("chalk"));
9const fs_1 = require("fs");
10const path_1 = __importDefault(require("path"));
11const PackageManager_1 = require("./PackageManager");
12class CocoaPodsError extends Error {
13 constructor(message, code, cause) {
14 super(cause ? `${message}\n└─ Cause: ${cause.message}` : message);
15 this.code = code;
16 this.cause = cause;
17 this.name = 'CocoaPodsError';
18 this.isPackageManagerError = true;
19 }
20}
21exports.CocoaPodsError = CocoaPodsError;
22function extractMissingDependencyError(error) {
23 // [!] Unable to find a specification for `expo-dev-menu-interface` depended upon by `expo-dev-launcher`
24 const results = error.match(/Unable to find a specification for ['"`]([\w-_\d\s]+)['"`] depended upon by ['"`]([\w-_\d\s]+)['"`]/);
25 if (results) {
26 return [results[1], results[2]];
27 }
28 return null;
29}
30exports.extractMissingDependencyError = extractMissingDependencyError;
31class CocoaPodsPackageManager {
32 constructor({ cwd, silent }) {
33 this.silent = !!silent;
34 this.options = {
35 cwd,
36 ...(silent
37 ? { stdio: 'pipe' }
38 : {
39 stdio: ['inherit', 'inherit', 'pipe'],
40 }),
41 };
42 }
43 static getPodProjectRoot(projectRoot) {
44 if (CocoaPodsPackageManager.isUsingPods(projectRoot))
45 return projectRoot;
46 const iosProject = path_1.default.join(projectRoot, 'ios');
47 if (CocoaPodsPackageManager.isUsingPods(iosProject))
48 return iosProject;
49 const macOsProject = path_1.default.join(projectRoot, 'macos');
50 if (CocoaPodsPackageManager.isUsingPods(macOsProject))
51 return macOsProject;
52 return null;
53 }
54 static isUsingPods(projectRoot) {
55 return fs_1.existsSync(path_1.default.join(projectRoot, 'Podfile'));
56 }
57 static async gemInstallCLIAsync(nonInteractive = false, spawnOptions = { stdio: 'inherit' }) {
58 const options = ['install', 'cocoapods', '--no-document'];
59 try {
60 // In case the user has run sudo before running the command we can properly install CocoaPods without prompting for an interaction.
61 await spawn_async_1.default('gem', options, spawnOptions);
62 }
63 catch (error) {
64 if (nonInteractive) {
65 throw new CocoaPodsError('Failed to install CocoaPods CLI with gem (recommended)', 'COMMAND_FAILED', error);
66 }
67 // If the user doesn't have permission then we can prompt them to use sudo.
68 await PackageManager_1.spawnSudoAsync(['gem', ...options], spawnOptions);
69 }
70 }
71 static async brewLinkCLIAsync(spawnOptions = { stdio: 'inherit' }) {
72 await spawn_async_1.default('brew', ['link', 'cocoapods'], spawnOptions);
73 }
74 static async brewInstallCLIAsync(spawnOptions = { stdio: 'inherit' }) {
75 await spawn_async_1.default('brew', ['install', 'cocoapods'], spawnOptions);
76 }
77 static async installCLIAsync({ nonInteractive = false, spawnOptions = { stdio: 'inherit' }, }) {
78 var _a;
79 if (!spawnOptions) {
80 spawnOptions = { stdio: 'inherit' };
81 }
82 const silent = !!spawnOptions.ignoreStdio;
83 try {
84 !silent && console.log(`\u203A Attempting to install CocoaPods CLI with Gem`);
85 await CocoaPodsPackageManager.gemInstallCLIAsync(nonInteractive, spawnOptions);
86 !silent && console.log(`\u203A Successfully installed CocoaPods CLI with Gem`);
87 return true;
88 }
89 catch (error) {
90 if (!silent) {
91 console.log(chalk_1.default.yellow(`\u203A Failed to install CocoaPods CLI with Gem`));
92 console.log(chalk_1.default.red((_a = error.stderr) !== null && _a !== void 0 ? _a : error.message));
93 console.log(`\u203A Attempting to install CocoaPods CLI with Homebrew`);
94 }
95 try {
96 await CocoaPodsPackageManager.brewInstallCLIAsync(spawnOptions);
97 if (!(await CocoaPodsPackageManager.isCLIInstalledAsync(spawnOptions))) {
98 try {
99 await CocoaPodsPackageManager.brewLinkCLIAsync(spawnOptions);
100 // Still not available after linking? Bail out
101 if (!(await CocoaPodsPackageManager.isCLIInstalledAsync(spawnOptions))) {
102 throw new CocoaPodsError('CLI could not be installed automatically with gem or Homebrew, please install CocoaPods manually and try again', 'NO_CLI', error);
103 }
104 }
105 catch (error) {
106 throw new CocoaPodsError('Homebrew installation appeared to succeed but CocoaPods CLI not found in PATH and unable to link.', 'NO_CLI', error);
107 }
108 }
109 !silent && console.log(`\u203A Successfully installed CocoaPods CLI with Homebrew`);
110 return true;
111 }
112 catch (error) {
113 !silent &&
114 console.warn(chalk_1.default.yellow(`\u203A Failed to install CocoaPods with Homebrew. Please install CocoaPods CLI manually and try again.`));
115 throw new CocoaPodsError(`Failed to install CocoaPods with Homebrew. Please install CocoaPods CLI manually and try again.`, 'NO_CLI', error);
116 }
117 }
118 }
119 static isAvailable(projectRoot, silent) {
120 if (process.platform !== 'darwin') {
121 !silent && console.log(chalk_1.default.red('CocoaPods is only supported on macOS machines'));
122 return false;
123 }
124 if (!CocoaPodsPackageManager.isUsingPods(projectRoot)) {
125 !silent && console.log(chalk_1.default.yellow('CocoaPods is not supported in this project'));
126 return false;
127 }
128 return true;
129 }
130 static async isCLIInstalledAsync(spawnOptions = { stdio: 'inherit' }) {
131 try {
132 await spawn_async_1.default('pod', ['--version'], spawnOptions);
133 return true;
134 }
135 catch {
136 return false;
137 }
138 }
139 get name() {
140 return 'CocoaPods';
141 }
142 async installAsync({ spinner } = {}) {
143 await this._installAsync({ spinner });
144 }
145 isCLIInstalledAsync() {
146 return CocoaPodsPackageManager.isCLIInstalledAsync(this.options);
147 }
148 installCLIAsync() {
149 return CocoaPodsPackageManager.installCLIAsync({
150 nonInteractive: true,
151 spawnOptions: this.options,
152 });
153 }
154 async _installAsync({ spinner, shouldUpdate = true, } = {}) {
155 var _a;
156 try {
157 return await this._runAsync(['install']);
158 }
159 catch (error) {
160 const output = error.output.join('\n').trim();
161 const isPodRepoUpdateError = output.includes('pod repo update');
162 // When pods are outdated, they'll throw an error informing you to run "pod repo update"
163 // Attempt to run that command and try installing again.
164 if (isPodRepoUpdateError && shouldUpdate) {
165 const warningInfo = extractMissingDependencyError(output);
166 let message;
167 if (warningInfo) {
168 message = `Couldn't install: ${warningInfo[1]} » ${chalk_1.default.underline(warningInfo[0])}.`;
169 }
170 else {
171 message = `Couldn't install Pods.`;
172 }
173 message += ` Updating the Pods project and trying again...`;
174 if (spinner) {
175 spinner.text = chalk_1.default.bold(message);
176 }
177 !this.silent && console.warn(chalk_1.default.yellow(message));
178 await this.podRepoUpdateAsync();
179 // Include a boolean to ensure pod repo update isn't invoked in the unlikely case where the pods fail to update.
180 return await this._installAsync({ spinner, shouldUpdate: false });
181 }
182 else {
183 const cwd = this.options.cwd || process.cwd();
184 if (error.stdout.match(/No [`'"]Podfile[`'"] found in the project directory/)) {
185 error.message = `No Podfile found in directory: ${cwd}. Ensure CocoaPods is setup any try again.`;
186 }
187 else if (isPodRepoUpdateError) {
188 const warningInfo = extractMissingDependencyError(output);
189 let reason;
190 if (warningInfo) {
191 reason = `Couldn't install: ${warningInfo[1]} » ${chalk_1.default.underline(warningInfo[0])}`;
192 }
193 else {
194 reason = `This is often due to native package versions mismatching`;
195 }
196 let solution;
197 if (warningInfo === null || warningInfo === void 0 ? void 0 : warningInfo[0]) {
198 // If the missing package is named `expo-dev-menu`, `react-native`, etc. then it might not be installed in the project.
199 if (warningInfo[0].match(/^(?:@?expo|@?react)(-|\/)/)) {
200 solution = `Ensure the node module "${warningInfo[0]}" is installed in your project, then run \`npx pod-install\` to try again.`;
201 }
202 else {
203 solution = `Ensure the CocoaPod "${warningInfo[0]}" is installed in your project, then run \`npx pod-install\` to try again.`;
204 }
205 }
206 else {
207 solution = `Try deleting the \`ios/Pods\` folder or the \`ios/Podfile.lock\` file and running \`npx pod-install\` to resolve.`;
208 }
209 error.message = `${reason}. ${solution}`;
210 throw new CocoaPodsError('Command `pod repo update` failed.', 'COMMAND_FAILED', error);
211 }
212 else {
213 let stderr = error.stderr.trim();
214 // CocoaPods CLI prints the useful error to stdout...
215 const usefulError = (_a = error.stdout.match(/\[!\]\s((?:.|\n)*)/)) === null || _a === void 0 ? void 0 : _a[1];
216 // If there is a useful error message then prune the less useful info.
217 if (usefulError) {
218 // Delete unhelpful CocoaPods CLI error message.
219 if (error.message.match(/pod exited with non-zero code: 1/)) {
220 error.message = null;
221 }
222 // Remove `<PBXResourcesBuildPhase UUID=`13B07F8E1A680F5B00A75B9A`>` type errors when useful messages exist.
223 if (stderr.match(/PBXResourcesBuildPhase/)) {
224 stderr = null;
225 }
226 }
227 error.message = [usefulError, error.message, stderr].filter(Boolean).join('\n');
228 }
229 throw new CocoaPodsError('Command `pod install` failed.', 'COMMAND_FAILED', error);
230 }
231 }
232 }
233 async addAsync(...names) {
234 throw new Error('Unimplemented');
235 }
236 async addDevAsync(...names) {
237 throw new Error('Unimplemented');
238 }
239 async versionAsync() {
240 const { stdout } = await spawn_async_1.default('pod', ['--version'], this.options);
241 return stdout.trim();
242 }
243 async getConfigAsync(key) {
244 throw new Error('Unimplemented');
245 }
246 async removeLockfileAsync() {
247 throw new Error('Unimplemented');
248 }
249 async cleanAsync() {
250 throw new Error('Unimplemented');
251 }
252 // Private
253 async podRepoUpdateAsync() {
254 var _a;
255 try {
256 await this._runAsync(['repo', 'update']);
257 }
258 catch (error) {
259 error.message = error.message || ((_a = error.stderr) !== null && _a !== void 0 ? _a : error.stdout);
260 throw new CocoaPodsError('The command `pod repo update` failed', 'COMMAND_FAILED', error);
261 }
262 }
263 async _runAsync(args) {
264 if (!this.silent) {
265 console.log(`> pod ${args.join(' ')}`);
266 }
267 return spawn_async_1.default('pod', [...args], this.options);
268 }
269}
270exports.CocoaPodsPackageManager = CocoaPodsPackageManager;
271//# sourceMappingURL=CocoaPodsPackageManager.js.map
\No newline at end of file