@expo/package-manager 0.0.0-canary-20231122-1af9191
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/LICENSE +22 -0
- package/README.md +41 -0
- package/build/PackageManager.d.ts +46 -0
- package/build/PackageManager.js +3 -0
- package/build/PackageManager.js.map +1 -0
- package/build/index.d.ts +9 -0
- package/build/index.js +28 -0
- package/build/index.js.map +1 -0
- package/build/ios/CocoaPodsPackageManager.d.ts +74 -0
- package/build/ios/CocoaPodsPackageManager.js +404 -0
- package/build/ios/CocoaPodsPackageManager.js.map +1 -0
- package/build/node/BasePackageManager.d.ts +32 -0
- package/build/node/BasePackageManager.js +64 -0
- package/build/node/BasePackageManager.js.map +1 -0
- package/build/node/BunPackageManager.d.ts +14 -0
- package/build/node/BunPackageManager.js +54 -0
- package/build/node/BunPackageManager.js.map +1 -0
- package/build/node/NpmPackageManager.d.ts +24 -0
- package/build/node/NpmPackageManager.js +112 -0
- package/build/node/NpmPackageManager.js.map +1 -0
- package/build/node/PnpmPackageManager.d.ts +14 -0
- package/build/node/PnpmPackageManager.js +61 -0
- package/build/node/PnpmPackageManager.js.map +1 -0
- package/build/node/YarnPackageManager.d.ts +16 -0
- package/build/node/YarnPackageManager.js +60 -0
- package/build/node/YarnPackageManager.js.map +1 -0
- package/build/utils/env.d.ts +6 -0
- package/build/utils/env.js +12 -0
- package/build/utils/env.js.map +1 -0
- package/build/utils/nodeManagers.d.ts +26 -0
- package/build/utils/nodeManagers.js +98 -0
- package/build/utils/nodeManagers.js.map +1 -0
- package/build/utils/nodeWorkspaces.d.ts +13 -0
- package/build/utils/nodeWorkspaces.js +62 -0
- package/build/utils/nodeWorkspaces.js.map +1 -0
- package/build/utils/spawn.d.ts +21 -0
- package/build/utils/spawn.js +57 -0
- package/build/utils/spawn.js.map +1 -0
- package/build/utils/yarn.d.ts +4 -0
- package/build/utils/yarn.js +47 -0
- package/build/utils/yarn.js.map +1 -0
- package/package.json +64 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!-- Title -->
|
|
2
|
+
<h1 align="center">
|
|
3
|
+
👋 Welcome to <br><code>@expo/package-manager</code>
|
|
4
|
+
</h1>
|
|
5
|
+
|
|
6
|
+
<p align="center">A library for installing and finding packages in a project.</p>
|
|
7
|
+
|
|
8
|
+
<!-- Header -->
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<img src="https://flat.badgen.net/packagephobia/install/@expo/package-manager">
|
|
12
|
+
|
|
13
|
+
<a href="https://www.npmjs.com/package/@expo/package-manager">
|
|
14
|
+
<img src="https://flat.badgen.net/npm/dw/@expo/package-manager" target="_blank" />
|
|
15
|
+
</a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
<!-- Body -->
|
|
21
|
+
|
|
22
|
+
## 🏁 Setup
|
|
23
|
+
|
|
24
|
+
Install `@expo/package-manager` in your project.
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
yarn add @expo/package-manager
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## ⚽️ Usage
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import * as PackageManager from '@expo/package-manager';
|
|
34
|
+
|
|
35
|
+
const manager = PackageManager.createForProject(projectRoot);
|
|
36
|
+
|
|
37
|
+
await Promise.all([
|
|
38
|
+
manager.addDevAsync(['@expo/webpack-config']),
|
|
39
|
+
manager.addAsync(['expo', 'expo-camera']),
|
|
40
|
+
]);
|
|
41
|
+
```
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { SpawnOptions, SpawnPromise, SpawnResult } from '@expo/spawn-async';
|
|
2
|
+
import { PendingSpawnPromise } from './utils/spawn';
|
|
3
|
+
export interface PackageManagerOptions extends SpawnOptions {
|
|
4
|
+
/**
|
|
5
|
+
* If the package manager should run in silent mode.
|
|
6
|
+
* Note, this will hide possible error output from executed commands.
|
|
7
|
+
* When running in silent mode, make sure you handle them properly.
|
|
8
|
+
*/
|
|
9
|
+
silent?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* The logging method used to communicate the command which is executed.
|
|
12
|
+
* Without `silent`, this defaults to `console.log`.
|
|
13
|
+
* When `silent` is set to `true`, this defaults to a no-op.
|
|
14
|
+
*/
|
|
15
|
+
log?: (...args: any[]) => void;
|
|
16
|
+
}
|
|
17
|
+
export interface PackageManager {
|
|
18
|
+
/** The options for this package manager */
|
|
19
|
+
readonly options: PackageManagerOptions;
|
|
20
|
+
/** Run any command using the package manager */
|
|
21
|
+
runAsync(command: string[]): SpawnPromise<SpawnResult>;
|
|
22
|
+
/** Get the version of the used package manager */
|
|
23
|
+
versionAsync(): Promise<string>;
|
|
24
|
+
/** Get a single configuration property from the package manager */
|
|
25
|
+
getConfigAsync(key: string): Promise<string>;
|
|
26
|
+
/** Remove the lock file within the project, if any */
|
|
27
|
+
removeLockfileAsync(): Promise<void>;
|
|
28
|
+
/** Get the workspace root package manager, if this project is within a workspace/monorepo */
|
|
29
|
+
workspaceRoot(): PackageManager | null;
|
|
30
|
+
/** Install all current dependencies using the package manager */
|
|
31
|
+
installAsync(): Promise<SpawnResult> | SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>;
|
|
32
|
+
/** Uninstall all current dependencies by removing the folder containing the packages */
|
|
33
|
+
uninstallAsync(): Promise<void>;
|
|
34
|
+
/** Add a normal dependency to the project */
|
|
35
|
+
addAsync(namesOrFlags: string[]): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>;
|
|
36
|
+
/** Add a development dependency to the project */
|
|
37
|
+
addDevAsync(namesOrFlags: string[]): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>;
|
|
38
|
+
/** Add a global dependency to the environment */
|
|
39
|
+
addGlobalAsync(namesOrFlags: string[]): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>;
|
|
40
|
+
/** Remove a normal dependency from the project */
|
|
41
|
+
removeAsync(namesOrFlags: string[]): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>;
|
|
42
|
+
/** Remove a development dependency from the project */
|
|
43
|
+
removeDevAsync(namesOrFlags: string[]): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>;
|
|
44
|
+
/** Remove a global dependency from the environments */
|
|
45
|
+
removeGlobalAsync(namesOrFlags: string[]): SpawnPromise<SpawnResult> | PendingSpawnPromise<SpawnResult>;
|
|
46
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PackageManager.js","sourceRoot":"","sources":["../src/PackageManager.ts"],"names":[],"mappings":""}
|
package/build/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './PackageManager';
|
|
2
|
+
export * from './ios/CocoaPodsPackageManager';
|
|
3
|
+
export * from './node/NpmPackageManager';
|
|
4
|
+
export * from './node/PnpmPackageManager';
|
|
5
|
+
export * from './node/YarnPackageManager';
|
|
6
|
+
export * from './node/BunPackageManager';
|
|
7
|
+
export * from './utils/nodeManagers';
|
|
8
|
+
export * from './utils/nodeWorkspaces';
|
|
9
|
+
export { isYarnOfflineAsync } from './utils/yarn';
|
package/build/index.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.isYarnOfflineAsync = void 0;
|
|
18
|
+
__exportStar(require("./PackageManager"), exports);
|
|
19
|
+
__exportStar(require("./ios/CocoaPodsPackageManager"), exports);
|
|
20
|
+
__exportStar(require("./node/NpmPackageManager"), exports);
|
|
21
|
+
__exportStar(require("./node/PnpmPackageManager"), exports);
|
|
22
|
+
__exportStar(require("./node/YarnPackageManager"), exports);
|
|
23
|
+
__exportStar(require("./node/BunPackageManager"), exports);
|
|
24
|
+
__exportStar(require("./utils/nodeManagers"), exports);
|
|
25
|
+
__exportStar(require("./utils/nodeWorkspaces"), exports);
|
|
26
|
+
var yarn_1 = require("./utils/yarn");
|
|
27
|
+
Object.defineProperty(exports, "isYarnOfflineAsync", { enumerable: true, get: function () { return yarn_1.isYarnOfflineAsync; } });
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;AAAA,mDAAiC;AAEjC,gEAA8C;AAE9C,2DAAyC;AACzC,4DAA0C;AAC1C,4DAA0C;AAC1C,2DAAyC;AAEzC,uDAAqC;AACrC,yDAAuC;AACvC,qCAAkD;AAAzC,0GAAA,kBAAkB,OAAA"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import spawnAsync, { SpawnOptions, SpawnResult } from '@expo/spawn-async';
|
|
2
|
+
import { Ora } from 'ora';
|
|
3
|
+
export type CocoaPodsErrorCode = 'NON_INTERACTIVE' | 'NO_CLI' | 'COMMAND_FAILED';
|
|
4
|
+
export declare class CocoaPodsError extends Error {
|
|
5
|
+
code: CocoaPodsErrorCode;
|
|
6
|
+
cause?: Error | undefined;
|
|
7
|
+
readonly name = "CocoaPodsError";
|
|
8
|
+
readonly isPackageManagerError = true;
|
|
9
|
+
constructor(message: string, code: CocoaPodsErrorCode, cause?: Error | undefined);
|
|
10
|
+
}
|
|
11
|
+
export declare function extractMissingDependencyError(errorOutput: string): [string, string] | null;
|
|
12
|
+
export declare class CocoaPodsPackageManager {
|
|
13
|
+
options: SpawnOptions;
|
|
14
|
+
private silent;
|
|
15
|
+
static getPodProjectRoot(projectRoot: string): string | null;
|
|
16
|
+
static isUsingPods(projectRoot: string): boolean;
|
|
17
|
+
static gemInstallCLIAsync(nonInteractive?: boolean, spawnOptions?: SpawnOptions): Promise<void>;
|
|
18
|
+
static brewLinkCLIAsync(spawnOptions?: SpawnOptions): Promise<void>;
|
|
19
|
+
static brewInstallCLIAsync(spawnOptions?: SpawnOptions): Promise<void>;
|
|
20
|
+
static installCLIAsync({ nonInteractive, spawnOptions, }: {
|
|
21
|
+
nonInteractive?: boolean;
|
|
22
|
+
spawnOptions?: SpawnOptions;
|
|
23
|
+
}): Promise<boolean>;
|
|
24
|
+
static isAvailable(projectRoot: string, silent: boolean): boolean;
|
|
25
|
+
static isCLIInstalledAsync(spawnOptions?: SpawnOptions): Promise<boolean>;
|
|
26
|
+
constructor({ cwd, silent }: {
|
|
27
|
+
cwd: string;
|
|
28
|
+
silent?: boolean;
|
|
29
|
+
});
|
|
30
|
+
get name(): string;
|
|
31
|
+
/** Runs `pod install` and attempts to automatically run known troubleshooting steps automatically. */
|
|
32
|
+
installAsync({ spinner }?: {
|
|
33
|
+
spinner?: Ora;
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
isCLIInstalledAsync(): Promise<boolean>;
|
|
36
|
+
installCLIAsync(): Promise<boolean>;
|
|
37
|
+
handleInstallErrorAsync({ error, shouldUpdate, updatedPackages, spinner, }: {
|
|
38
|
+
error: any;
|
|
39
|
+
spinner?: Ora;
|
|
40
|
+
shouldUpdate?: boolean;
|
|
41
|
+
updatedPackages?: string[];
|
|
42
|
+
}): Promise<spawnAsync.SpawnResult>;
|
|
43
|
+
private _installAsync;
|
|
44
|
+
private runInstallTypeCommandAsync;
|
|
45
|
+
addWithParametersAsync(names: string[], parameters: string[]): Promise<void>;
|
|
46
|
+
addAsync(names?: string[]): void;
|
|
47
|
+
addDevAsync(names?: string[]): void;
|
|
48
|
+
addGlobalAsync(names?: string[]): void;
|
|
49
|
+
removeAsync(names?: string[]): void;
|
|
50
|
+
removeDevAsync(names?: string[]): void;
|
|
51
|
+
removeGlobalAsync(names?: string[]): void;
|
|
52
|
+
versionAsync(): Promise<string>;
|
|
53
|
+
configAsync(key: string): Promise<string>;
|
|
54
|
+
removeLockfileAsync(): Promise<void>;
|
|
55
|
+
uninstallAsync(): Promise<void>;
|
|
56
|
+
private podRepoUpdateAsync;
|
|
57
|
+
_runAsync(args: string[]): Promise<SpawnResult>;
|
|
58
|
+
}
|
|
59
|
+
export declare function getPodUpdateMessage(output: string): {
|
|
60
|
+
updatePackage: string | null;
|
|
61
|
+
shouldUpdateRepo: boolean;
|
|
62
|
+
};
|
|
63
|
+
export declare function getPodRepoUpdateMessage(errorOutput: string): {
|
|
64
|
+
updatePackage: string | null;
|
|
65
|
+
shouldUpdateRepo: boolean;
|
|
66
|
+
message: string;
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* Format the CocoaPods CLI install error.
|
|
70
|
+
*
|
|
71
|
+
* @param error Error from CocoaPods CLI `pod install` command.
|
|
72
|
+
* @returns
|
|
73
|
+
*/
|
|
74
|
+
export declare function getImprovedPodInstallError(error: SpawnResult & Error, { cwd }: Pick<SpawnOptions, 'cwd'>): Error;
|
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getImprovedPodInstallError = exports.getPodRepoUpdateMessage = exports.getPodUpdateMessage = exports.CocoaPodsPackageManager = exports.extractMissingDependencyError = exports.CocoaPodsError = void 0;
|
|
7
|
+
const spawn_async_1 = __importDefault(require("@expo/spawn-async"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const fs_1 = require("fs");
|
|
10
|
+
const os_1 = __importDefault(require("os"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const spawn_1 = require("../utils/spawn");
|
|
13
|
+
class CocoaPodsError extends Error {
|
|
14
|
+
code;
|
|
15
|
+
cause;
|
|
16
|
+
name = 'CocoaPodsError';
|
|
17
|
+
isPackageManagerError = true;
|
|
18
|
+
constructor(message, code, cause) {
|
|
19
|
+
super(cause ? `${message}\n└─ Cause: ${cause.message}` : message);
|
|
20
|
+
this.code = code;
|
|
21
|
+
this.cause = cause;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
exports.CocoaPodsError = CocoaPodsError;
|
|
25
|
+
function extractMissingDependencyError(errorOutput) {
|
|
26
|
+
// [!] Unable to find a specification for `expo-dev-menu-interface` depended upon by `expo-dev-launcher`
|
|
27
|
+
const results = errorOutput.match(/Unable to find a specification for ['"`]([\w-_\d\s]+)['"`] depended upon by ['"`]([\w-_\d\s]+)['"`]/);
|
|
28
|
+
if (results) {
|
|
29
|
+
return [results[1], results[2]];
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
exports.extractMissingDependencyError = extractMissingDependencyError;
|
|
34
|
+
class CocoaPodsPackageManager {
|
|
35
|
+
options;
|
|
36
|
+
silent;
|
|
37
|
+
static getPodProjectRoot(projectRoot) {
|
|
38
|
+
if (CocoaPodsPackageManager.isUsingPods(projectRoot))
|
|
39
|
+
return projectRoot;
|
|
40
|
+
const iosProject = path_1.default.join(projectRoot, 'ios');
|
|
41
|
+
if (CocoaPodsPackageManager.isUsingPods(iosProject))
|
|
42
|
+
return iosProject;
|
|
43
|
+
const macOsProject = path_1.default.join(projectRoot, 'macos');
|
|
44
|
+
if (CocoaPodsPackageManager.isUsingPods(macOsProject))
|
|
45
|
+
return macOsProject;
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
static isUsingPods(projectRoot) {
|
|
49
|
+
return (0, fs_1.existsSync)(path_1.default.join(projectRoot, 'Podfile'));
|
|
50
|
+
}
|
|
51
|
+
static async gemInstallCLIAsync(nonInteractive = false, spawnOptions = { stdio: 'inherit' }) {
|
|
52
|
+
const options = ['install', 'cocoapods', '--no-document'];
|
|
53
|
+
try {
|
|
54
|
+
// In case the user has run sudo before running the command we can properly install CocoaPods without prompting for an interaction.
|
|
55
|
+
await (0, spawn_async_1.default)('gem', options, spawnOptions);
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
if (nonInteractive) {
|
|
59
|
+
throw new CocoaPodsError('Failed to install CocoaPods CLI with gem (recommended)', 'COMMAND_FAILED', error);
|
|
60
|
+
}
|
|
61
|
+
// If the user doesn't have permission then we can prompt them to use sudo.
|
|
62
|
+
await (0, spawn_1.spawnSudoAsync)(['gem', ...options], spawnOptions);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
static async brewLinkCLIAsync(spawnOptions = { stdio: 'inherit' }) {
|
|
66
|
+
await (0, spawn_async_1.default)('brew', ['link', 'cocoapods'], spawnOptions);
|
|
67
|
+
}
|
|
68
|
+
static async brewInstallCLIAsync(spawnOptions = { stdio: 'inherit' }) {
|
|
69
|
+
await (0, spawn_async_1.default)('brew', ['install', 'cocoapods'], spawnOptions);
|
|
70
|
+
}
|
|
71
|
+
static async installCLIAsync({ nonInteractive = false, spawnOptions = { stdio: 'inherit' }, }) {
|
|
72
|
+
if (!spawnOptions) {
|
|
73
|
+
spawnOptions = { stdio: 'inherit' };
|
|
74
|
+
}
|
|
75
|
+
const silent = !!spawnOptions.ignoreStdio;
|
|
76
|
+
try {
|
|
77
|
+
!silent && console.log(`\u203A Attempting to install CocoaPods CLI with Gem`);
|
|
78
|
+
await CocoaPodsPackageManager.gemInstallCLIAsync(nonInteractive, spawnOptions);
|
|
79
|
+
!silent && console.log(`\u203A Successfully installed CocoaPods CLI with Gem`);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
if (!silent) {
|
|
84
|
+
console.log(chalk_1.default.yellow(`\u203A Failed to install CocoaPods CLI with Gem`));
|
|
85
|
+
console.log(chalk_1.default.red(error.stderr ?? error.message));
|
|
86
|
+
console.log(`\u203A Attempting to install CocoaPods CLI with Homebrew`);
|
|
87
|
+
}
|
|
88
|
+
try {
|
|
89
|
+
await CocoaPodsPackageManager.brewInstallCLIAsync(spawnOptions);
|
|
90
|
+
if (!(await CocoaPodsPackageManager.isCLIInstalledAsync(spawnOptions))) {
|
|
91
|
+
try {
|
|
92
|
+
await CocoaPodsPackageManager.brewLinkCLIAsync(spawnOptions);
|
|
93
|
+
// Still not available after linking? Bail out
|
|
94
|
+
if (!(await CocoaPodsPackageManager.isCLIInstalledAsync(spawnOptions))) {
|
|
95
|
+
throw new CocoaPodsError('CLI could not be installed automatically with gem or Homebrew, please install CocoaPods manually and try again', 'NO_CLI', error);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
throw new CocoaPodsError('Homebrew installation appeared to succeed but CocoaPods CLI not found in PATH and unable to link.', 'NO_CLI', error);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
!silent && console.log(`\u203A Successfully installed CocoaPods CLI with Homebrew`);
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
!silent &&
|
|
107
|
+
console.warn(chalk_1.default.yellow(`\u203A Failed to install CocoaPods with Homebrew. Please install CocoaPods CLI manually and try again.`));
|
|
108
|
+
throw new CocoaPodsError(`Failed to install CocoaPods with Homebrew. Please install CocoaPods CLI manually and try again.`, 'NO_CLI', error);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
static isAvailable(projectRoot, silent) {
|
|
113
|
+
if (process.platform !== 'darwin') {
|
|
114
|
+
!silent && console.log(chalk_1.default.red('CocoaPods is only supported on macOS machines'));
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
if (!CocoaPodsPackageManager.isUsingPods(projectRoot)) {
|
|
118
|
+
!silent && console.log(chalk_1.default.yellow('CocoaPods is not supported in this project'));
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
static async isCLIInstalledAsync(spawnOptions = { stdio: 'inherit' }) {
|
|
124
|
+
try {
|
|
125
|
+
await (0, spawn_async_1.default)('pod', ['--version'], spawnOptions);
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
constructor({ cwd, silent }) {
|
|
133
|
+
this.silent = !!silent;
|
|
134
|
+
this.options = {
|
|
135
|
+
cwd,
|
|
136
|
+
// We use pipe by default instead of inherit so that we can capture stderr/stdout and process it for errors.
|
|
137
|
+
// Later we'll also pipe the stdout/stderr to the terminal when silent is false.
|
|
138
|
+
stdio: 'pipe',
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
get name() {
|
|
142
|
+
return 'CocoaPods';
|
|
143
|
+
}
|
|
144
|
+
/** Runs `pod install` and attempts to automatically run known troubleshooting steps automatically. */
|
|
145
|
+
async installAsync({ spinner } = {}) {
|
|
146
|
+
await this._installAsync({ spinner });
|
|
147
|
+
}
|
|
148
|
+
isCLIInstalledAsync() {
|
|
149
|
+
return CocoaPodsPackageManager.isCLIInstalledAsync(this.options);
|
|
150
|
+
}
|
|
151
|
+
installCLIAsync() {
|
|
152
|
+
return CocoaPodsPackageManager.installCLIAsync({
|
|
153
|
+
nonInteractive: true,
|
|
154
|
+
spawnOptions: this.options,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
async handleInstallErrorAsync({ error, shouldUpdate = true, updatedPackages = [], spinner, }) {
|
|
158
|
+
// Unknown errors are rethrown.
|
|
159
|
+
if (!error.output) {
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
// To emulate a `pod install --repo-update` error, enter your `ios/Podfile.lock` and change one of `PODS` version numbers to some lower value.
|
|
163
|
+
// const isPodRepoUpdateError = shouldPodRepoUpdate(output);
|
|
164
|
+
if (!shouldUpdate) {
|
|
165
|
+
// If we can't automatically fix the error, we'll just rethrow it with some known troubleshooting info.
|
|
166
|
+
throw getImprovedPodInstallError(error, {
|
|
167
|
+
cwd: this.options.cwd,
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
// Collect all of the spawn info.
|
|
171
|
+
const errorOutput = error.output.join(os_1.default.EOL).trim();
|
|
172
|
+
// Extract useful information from the error message and push it to the spinner.
|
|
173
|
+
const { updatePackage, shouldUpdateRepo } = getPodUpdateMessage(errorOutput);
|
|
174
|
+
if (!updatePackage || updatedPackages.includes(updatePackage)) {
|
|
175
|
+
// `pod install --repo-update`...
|
|
176
|
+
// Attempt to install again but this time with install --repo-update enabled.
|
|
177
|
+
return await this._installAsync({
|
|
178
|
+
spinner,
|
|
179
|
+
shouldRepoUpdate: true,
|
|
180
|
+
// Include a boolean to ensure pod install --repo-update isn't invoked in the unlikely case where the pods fail to update.
|
|
181
|
+
shouldUpdate: false,
|
|
182
|
+
updatedPackages,
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
// Store the package we should update to prevent a loop.
|
|
186
|
+
updatedPackages.push(updatePackage);
|
|
187
|
+
// If a single package is broken, we'll try to update it.
|
|
188
|
+
// You can manually test this by changing a version number in your `Podfile.lock`.
|
|
189
|
+
// Attempt `pod update <package> <--no-repo-update>` and then try again.
|
|
190
|
+
return await this.runInstallTypeCommandAsync(['update', updatePackage, shouldUpdateRepo ? '' : '--no-repo-update'].filter(Boolean), {
|
|
191
|
+
formatWarning() {
|
|
192
|
+
const updateMessage = `Failed to update ${chalk_1.default.bold(updatePackage)}. Attempting to update the repo instead.`;
|
|
193
|
+
return updateMessage;
|
|
194
|
+
},
|
|
195
|
+
spinner,
|
|
196
|
+
updatedPackages,
|
|
197
|
+
});
|
|
198
|
+
// // If update succeeds, we'll try to install again (skipping `pod install --repo-update`).
|
|
199
|
+
// return await this._installAsync({
|
|
200
|
+
// spinner,
|
|
201
|
+
// shouldUpdate: false,
|
|
202
|
+
// updatedPackages,
|
|
203
|
+
// });
|
|
204
|
+
}
|
|
205
|
+
async _installAsync({ shouldRepoUpdate, ...props } = {}) {
|
|
206
|
+
return await this.runInstallTypeCommandAsync(['install', shouldRepoUpdate ? '--repo-update' : ''].filter(Boolean), {
|
|
207
|
+
formatWarning(error) {
|
|
208
|
+
// Extract useful information from the error message and push it to the spinner.
|
|
209
|
+
return getPodRepoUpdateMessage(error.output.join(os_1.default.EOL).trim()).message;
|
|
210
|
+
},
|
|
211
|
+
...props,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
async runInstallTypeCommandAsync(command, { formatWarning, ...props } = {}) {
|
|
215
|
+
try {
|
|
216
|
+
return await this._runAsync(command);
|
|
217
|
+
}
|
|
218
|
+
catch (error) {
|
|
219
|
+
if (formatWarning) {
|
|
220
|
+
const warning = formatWarning(error);
|
|
221
|
+
if (props.spinner) {
|
|
222
|
+
props.spinner.text = chalk_1.default.bold(warning);
|
|
223
|
+
}
|
|
224
|
+
if (!this.silent) {
|
|
225
|
+
console.warn(chalk_1.default.yellow(warning));
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return await this.handleInstallErrorAsync({ error, ...props });
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async addWithParametersAsync(names, parameters) {
|
|
232
|
+
throw new Error('Unimplemented');
|
|
233
|
+
}
|
|
234
|
+
addAsync(names = []) {
|
|
235
|
+
throw new Error('Unimplemented');
|
|
236
|
+
}
|
|
237
|
+
addDevAsync(names = []) {
|
|
238
|
+
throw new Error('Unimplemented');
|
|
239
|
+
}
|
|
240
|
+
addGlobalAsync(names = []) {
|
|
241
|
+
throw new Error('Unimplemented');
|
|
242
|
+
}
|
|
243
|
+
removeAsync(names = []) {
|
|
244
|
+
throw new Error('Unimplemented');
|
|
245
|
+
}
|
|
246
|
+
removeDevAsync(names = []) {
|
|
247
|
+
throw new Error('Unimplemented');
|
|
248
|
+
}
|
|
249
|
+
removeGlobalAsync(names = []) {
|
|
250
|
+
throw new Error('Unimplemented');
|
|
251
|
+
}
|
|
252
|
+
async versionAsync() {
|
|
253
|
+
const { stdout } = await (0, spawn_async_1.default)('pod', ['--version'], this.options);
|
|
254
|
+
return stdout.trim();
|
|
255
|
+
}
|
|
256
|
+
async configAsync(key) {
|
|
257
|
+
throw new Error('Unimplemented');
|
|
258
|
+
}
|
|
259
|
+
async removeLockfileAsync() {
|
|
260
|
+
throw new Error('Unimplemented');
|
|
261
|
+
}
|
|
262
|
+
async uninstallAsync() {
|
|
263
|
+
throw new Error('Unimplemented');
|
|
264
|
+
}
|
|
265
|
+
// Private
|
|
266
|
+
async podRepoUpdateAsync() {
|
|
267
|
+
try {
|
|
268
|
+
await this._runAsync(['repo', 'update']);
|
|
269
|
+
}
|
|
270
|
+
catch (error) {
|
|
271
|
+
error.message = error.message || (error.stderr ?? error.stdout);
|
|
272
|
+
throw new CocoaPodsError('The command `pod install --repo-update` failed', 'COMMAND_FAILED', error);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
// Exposed for testing
|
|
276
|
+
async _runAsync(args) {
|
|
277
|
+
if (!this.silent) {
|
|
278
|
+
console.log(`> pod ${args.join(' ')}`);
|
|
279
|
+
}
|
|
280
|
+
const promise = (0, spawn_async_1.default)('pod', [
|
|
281
|
+
...args,
|
|
282
|
+
// Enables colors while collecting output.
|
|
283
|
+
'--ansi',
|
|
284
|
+
], {
|
|
285
|
+
// Add the cwd and other options to the spawn options.
|
|
286
|
+
...this.options,
|
|
287
|
+
// We use pipe by default instead of inherit so that we can capture stderr/stdout and process it for errors.
|
|
288
|
+
// This is particularly required for the `pod install --repo-update` error.
|
|
289
|
+
// Later we'll also pipe the stdout/stderr to the terminal when silent is false,
|
|
290
|
+
// currently this means we lose out on the ansi colors unless passing the `--ansi` flag to every command.
|
|
291
|
+
stdio: 'pipe',
|
|
292
|
+
});
|
|
293
|
+
if (!this.silent) {
|
|
294
|
+
// If not silent, pipe the stdout/stderr to the terminal.
|
|
295
|
+
// We only do this when the `stdio` is set to `pipe` (collect the results for parsing), `inherit` won't contain `promise.child`.
|
|
296
|
+
if (promise.child.stdout) {
|
|
297
|
+
promise.child.stdout.pipe(process.stdout);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return await promise;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
exports.CocoaPodsPackageManager = CocoaPodsPackageManager;
|
|
304
|
+
/** When pods are outdated, they'll throw an error informing you to run "pod install --repo-update" */
|
|
305
|
+
function shouldPodRepoUpdate(errorOutput) {
|
|
306
|
+
const output = errorOutput;
|
|
307
|
+
const isPodRepoUpdateError = output.includes('pod repo update') || output.includes('--no-repo-update');
|
|
308
|
+
return isPodRepoUpdateError;
|
|
309
|
+
}
|
|
310
|
+
function getPodUpdateMessage(output) {
|
|
311
|
+
const props = output.match(/run ['"`]pod update ([\w-_\d/]+)( --no-repo-update)?['"`] to apply changes/);
|
|
312
|
+
return {
|
|
313
|
+
updatePackage: props?.[1] ?? null,
|
|
314
|
+
shouldUpdateRepo: !props?.[2],
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
exports.getPodUpdateMessage = getPodUpdateMessage;
|
|
318
|
+
function getPodRepoUpdateMessage(errorOutput) {
|
|
319
|
+
const warningInfo = extractMissingDependencyError(errorOutput);
|
|
320
|
+
const brokenPackage = getPodUpdateMessage(errorOutput);
|
|
321
|
+
let message;
|
|
322
|
+
if (warningInfo) {
|
|
323
|
+
message = `Couldn't install: ${warningInfo[1]} » ${chalk_1.default.underline(warningInfo[0])}.`;
|
|
324
|
+
}
|
|
325
|
+
else if (brokenPackage?.updatePackage) {
|
|
326
|
+
message = `Couldn't install: ${brokenPackage?.updatePackage}.`;
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
message = `Couldn't install Pods.`;
|
|
330
|
+
}
|
|
331
|
+
message += ` Updating the Pods project and trying again...`;
|
|
332
|
+
return { message, ...brokenPackage };
|
|
333
|
+
}
|
|
334
|
+
exports.getPodRepoUpdateMessage = getPodRepoUpdateMessage;
|
|
335
|
+
/**
|
|
336
|
+
* Format the CocoaPods CLI install error.
|
|
337
|
+
*
|
|
338
|
+
* @param error Error from CocoaPods CLI `pod install` command.
|
|
339
|
+
* @returns
|
|
340
|
+
*/
|
|
341
|
+
function getImprovedPodInstallError(error, { cwd = process.cwd() }) {
|
|
342
|
+
// Collect all of the spawn info.
|
|
343
|
+
const errorOutput = error.output.join(os_1.default.EOL).trim();
|
|
344
|
+
if (error.stdout.match(/No [`'"]Podfile[`'"] found in the project directory/)) {
|
|
345
|
+
// Ran pod install but no Podfile was found.
|
|
346
|
+
error.message = `No Podfile found in directory: ${cwd}. Ensure CocoaPods is setup any try again.`;
|
|
347
|
+
}
|
|
348
|
+
else if (shouldPodRepoUpdate(errorOutput)) {
|
|
349
|
+
// Ran pod install but the install --repo-update step failed.
|
|
350
|
+
const warningInfo = extractMissingDependencyError(errorOutput);
|
|
351
|
+
let reason;
|
|
352
|
+
if (warningInfo) {
|
|
353
|
+
reason = `Couldn't install: ${warningInfo[1]} » ${chalk_1.default.underline(warningInfo[0])}`;
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
reason = `This is often due to native package versions mismatching`;
|
|
357
|
+
}
|
|
358
|
+
// Attempt to provide a helpful message about the missing NPM dependency (containing a CocoaPod) since React Native
|
|
359
|
+
// developers will almost always be using autolinking and not interacting with CocoaPods directly.
|
|
360
|
+
let solution;
|
|
361
|
+
if (warningInfo?.[0]) {
|
|
362
|
+
// If the missing package is named `expo-dev-menu`, `react-native`, etc. then it might not be installed in the project.
|
|
363
|
+
if (warningInfo[0].match(/^(?:@?expo|@?react)(-|\/)/)) {
|
|
364
|
+
solution = `Ensure the node module "${warningInfo[0]}" is installed in your project, then run 'npx pod-install' to try again.`;
|
|
365
|
+
}
|
|
366
|
+
else {
|
|
367
|
+
solution = `Ensure the CocoaPod "${warningInfo[0]}" is installed in your project, then run 'npx pod-install' to try again.`;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
// Brute force
|
|
372
|
+
solution = `Try deleting the 'ios/Pods' folder or the 'ios/Podfile.lock' file and running 'npx pod-install' to resolve.`;
|
|
373
|
+
}
|
|
374
|
+
error.message = `${reason}. ${solution}`;
|
|
375
|
+
// Attempt to provide the troubleshooting info from CocoaPods CLI at the bottom of the error message.
|
|
376
|
+
if (error.stdout) {
|
|
377
|
+
const cocoapodsDebugInfo = error.stdout.split(os_1.default.EOL);
|
|
378
|
+
// The troubleshooting info starts with `[!]`, capture everything after that.
|
|
379
|
+
const firstWarning = cocoapodsDebugInfo.findIndex((v) => v.startsWith('[!]'));
|
|
380
|
+
if (firstWarning !== -1) {
|
|
381
|
+
const warning = cocoapodsDebugInfo.slice(firstWarning).join(os_1.default.EOL);
|
|
382
|
+
error.message += `\n\n${chalk_1.default.gray(warning)}`;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
return new CocoaPodsError('Command `pod install --repo-update` failed.', 'COMMAND_FAILED', error);
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
let stderr = error.stderr.trim();
|
|
389
|
+
// CocoaPods CLI prints the useful error to stdout...
|
|
390
|
+
const usefulError = error.stdout.match(/\[!\]\s((?:.|\n)*)/)?.[1];
|
|
391
|
+
// If there is a useful error message then prune the less useful info.
|
|
392
|
+
if (usefulError) {
|
|
393
|
+
// Delete unhelpful CocoaPods CLI error message.
|
|
394
|
+
if (error.message?.match(/pod exited with non-zero code: 1/)) {
|
|
395
|
+
error.message = '';
|
|
396
|
+
}
|
|
397
|
+
stderr = null;
|
|
398
|
+
}
|
|
399
|
+
error.message = [usefulError, error.message, stderr].filter(Boolean).join('\n');
|
|
400
|
+
}
|
|
401
|
+
return new CocoaPodsError('Command `pod install` failed.', 'COMMAND_FAILED', error);
|
|
402
|
+
}
|
|
403
|
+
exports.getImprovedPodInstallError = getImprovedPodInstallError;
|
|
404
|
+
//# sourceMappingURL=CocoaPodsPackageManager.js.map
|