Skip to content

Commit c578acc

Browse files
refactor: move executePodInstall method to CocoapodsService
The CocoapodsService is designed to execute all pod related operations, so move the `executePodInstall` method from `IosProjectService` to `CocoapodsService`.
1 parent ccfce12 commit c578acc

File tree

5 files changed

+76
-60
lines changed

5 files changed

+76
-60
lines changed

lib/constants.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,3 +222,8 @@ export class PluginNativeDirNames {
222222
}
223223

224224
export const PODFILE_NAME = "Podfile";
225+
226+
export class IosProjectConstants {
227+
public static XcodeProjExtName = ".xcodeproj";
228+
public static XcodeSchemeExtName = ".xcscheme";
229+
}

lib/definitions/project.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,15 @@ interface ICocoaPodsService {
493493
* @returns {string} Path to project's Podfile.
494494
*/
495495
getProjectPodfilePath(nativeProjectPath: string): string;
496+
497+
/**
498+
* Executes `pod install` or `sanboxpod install` in the passed project.
499+
* @param {IProjectData} projectData Information about the project.
500+
* @param {string} projectRoot The root directory of the native iOS project.
501+
* @param {string} xcodeProjPath The full path to the .xcodeproj file.
502+
* @returns {Promise<ISpawnResult>} Information about the spawned process.
503+
*/
504+
executePodInstall(projectData: IProjectData, projectRoot: string, xcodeProjPath: string): Promise<ISpawnResult>;
496505
}
497506

498507
interface IRubyFunction {

lib/services/cocoapods-service.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ export class CocoaPodsService implements ICocoaPodsService {
66
private static PODFILE_POST_INSTALL_SECTION_NAME = "post_install";
77
private static INSTALLER_BLOCK_PARAMETER_NAME = "installer";
88

9-
constructor(private $fs: IFileSystem) { }
9+
constructor(private $fs: IFileSystem,
10+
private $childProcess: IChildProcess,
11+
private $errors: IErrors,
12+
private $xcprojService: IXcprojService,
13+
private $logger: ILogger,
14+
private $config: IConfiguration) { }
1015

1116
public getPodfileHeader(targetName: string): string {
1217
return `use_frameworks!${EOL}${EOL}target "${targetName}" do${EOL}`;
@@ -20,6 +25,43 @@ export class CocoaPodsService implements ICocoaPodsService {
2025
return path.join(projectRoot, PODFILE_NAME);
2126
}
2227

28+
public async executePodInstall(projectData: IProjectData, projectRoot: string, xcodeProjPath: string): Promise<ISpawnResult> {
29+
// Check availability
30+
try {
31+
await this.$childProcess.exec("which pod");
32+
await this.$childProcess.exec("which xcodeproj");
33+
} catch (e) {
34+
this.$errors.failWithoutHelp("CocoaPods or ruby gem 'xcodeproj' is not installed. Run `sudo gem install cocoapods` and try again.");
35+
}
36+
37+
await this.$xcprojService.verifyXcproj(true);
38+
39+
this.$logger.info("Installing pods...");
40+
const podTool = this.$config.USE_POD_SANDBOX ? "sandbox-pod" : "pod";
41+
const podInstallResult = await this.$childProcess.spawnFromEvent(podTool, ["install"], "close", { cwd: projectRoot, stdio: ['pipe', process.stdout, 'pipe'] });
42+
if (podInstallResult.stderr) {
43+
const warnings = podInstallResult.stderr.match(/(\u001b\[(?:\d*;){0,5}\d*m[\s\S]+?\u001b\[(?:\d*;){0,5}\d*m)|(\[!\].*?\n)|(.*?warning.*)/gi);
44+
_.each(warnings, (warning: string) => {
45+
this.$logger.warnWithLabel(warning.replace("\n", ""));
46+
});
47+
48+
let errors = podInstallResult.stderr;
49+
_.each(warnings, warning => {
50+
errors = errors.replace(warning, "");
51+
});
52+
53+
if (errors.trim()) {
54+
this.$errors.failWithoutHelp(`Pod install command failed. Error output: ${errors}`);
55+
}
56+
}
57+
58+
if ((await this.$xcprojService.getXcprojInfo()).shouldUseXcproj) {
59+
await this.$childProcess.spawnFromEvent("xcproj", ["--project", xcodeProjPath, "touch"], "close");
60+
}
61+
62+
return podInstallResult;
63+
}
64+
2365
public async applyPluginPodfileToProject(pluginData: IPluginData, projectData: IProjectData, nativeProjectPath: string): Promise<void> {
2466
const pluginPodFilePath = this.getPluginPodfilePath(pluginData);
2567
if (!this.$fs.exists(pluginPodFilePath)) {

lib/services/ios-project-service.ts

Lines changed: 13 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { IOSProvisionService } from "./ios-provision-service";
1313
import { IOSEntitlementsService } from "./ios-entitlements-service";
1414
import { XCConfigService } from "./xcconfig-service";
1515
import * as mobileprovision from "ios-mobileprovision-finder";
16-
import { BUILD_XCCONFIG_FILE_NAME } from "../constants";
16+
import { BUILD_XCCONFIG_FILE_NAME, IosProjectConstants } from "../constants";
1717

1818
interface INativeSourceCodeGroup {
1919
name: string;
@@ -22,8 +22,6 @@ interface INativeSourceCodeGroup {
2222
}
2323

2424
export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServiceBase implements IPlatformProjectService {
25-
private static XCODE_PROJECT_EXT_NAME = ".xcodeproj";
26-
private static XCODE_SCHEME_EXT_NAME = ".xcscheme";
2725
private static XCODEBUILD_MIN_VERSION = "6.0";
2826
private static IOS_PROJECT_NAME_PLACEHOLDER = "__PROJECT_NAME__";
2927
private static IOS_PLATFORM_NAME = "ios";
@@ -36,7 +34,6 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
3634
private $injector: IInjector,
3735
$projectDataService: IProjectDataService,
3836
private $prompter: IPrompter,
39-
private $config: IConfiguration,
4037
private $devicePlatformsConstants: Mobile.IDevicePlatformsConstants,
4138
private $devicesService: Mobile.IDevicesService,
4239
private $mobileHelper: Mobile.IMobileHelper,
@@ -174,21 +171,21 @@ export class IOSProjectService extends projectServiceBaseLib.PlatformProjectServ
174171
}
175172
this.replaceFileName("-Prefix.pch", projectRootFilePath, projectData);
176173

177-
const xcschemeDirPath = path.join(this.getPlatformData(projectData).projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER + IOSProjectService.XCODE_PROJECT_EXT_NAME, "xcshareddata/xcschemes");
178-
const xcschemeFilePath = path.join(xcschemeDirPath, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER + IOSProjectService.XCODE_SCHEME_EXT_NAME);
174+
const xcschemeDirPath = path.join(this.getPlatformData(projectData).projectRoot, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER + IosProjectConstants.XcodeProjExtName, "xcshareddata/xcschemes");
175+
const xcschemeFilePath = path.join(xcschemeDirPath, IOSProjectService.IOS_PROJECT_NAME_PLACEHOLDER + IosProjectConstants.XcodeSchemeExtName);
179176

180177
if (this.$fs.exists(xcschemeFilePath)) {
181178
this.$logger.debug("Found shared scheme at xcschemeFilePath, renaming to match project name.");
182179
this.$logger.debug("Checkpoint 0");
183180
this.replaceFileContent(xcschemeFilePath, projectData);
184181
this.$logger.debug("Checkpoint 1");
185-
this.replaceFileName(IOSProjectService.XCODE_SCHEME_EXT_NAME, xcschemeDirPath, projectData);
182+
this.replaceFileName(IosProjectConstants.XcodeSchemeExtName, xcschemeDirPath, projectData);
186183
this.$logger.debug("Checkpoint 2");
187184
} else {
188185
this.$logger.debug("Copying xcscheme from template not found at " + xcschemeFilePath);
189186
}
190187

191-
this.replaceFileName(IOSProjectService.XCODE_PROJECT_EXT_NAME, this.getPlatformData(projectData).projectRoot, projectData);
188+
this.replaceFileName(IosProjectConstants.XcodeProjExtName, this.getPlatformData(projectData).projectRoot, projectData);
192189

193190
const pbxprojFilePath = this.getPbxProjPath(projectData);
194191
this.replaceFileContent(pbxprojFilePath, projectData);
@@ -891,7 +888,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
891888
}
892889

893890
private getXcodeprojPath(projectData: IProjectData): string {
894-
return path.join(this.getPlatformData(projectData).projectRoot, projectData.projectName + IOSProjectService.XCODE_PROJECT_EXT_NAME);
891+
return path.join(this.getPlatformData(projectData).projectRoot, projectData.projectName + IosProjectConstants.XcodeProjExtName);
895892
}
896893

897894
private getPluginsDebugXcconfigFilePath(projectData: IProjectData): string {
@@ -941,7 +938,9 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
941938
await this.prepareResources(pluginPlatformsFolderPath, pluginData, projectData);
942939
await this.prepareFrameworks(pluginPlatformsFolderPath, pluginData, projectData);
943940
await this.prepareStaticLibs(pluginPlatformsFolderPath, pluginData, projectData);
944-
await this.prepareCocoapods(pluginPlatformsFolderPath, pluginData, projectData);
941+
942+
const projectRoot = this.getPlatformData(projectData).projectRoot;
943+
await this.$cocoapodsService.applyPluginPodfileToProject(pluginData, projectData, projectRoot);
945944
}
946945

947946
public async removePluginNativeCode(pluginData: IPluginData, projectData: IProjectData): Promise<void> {
@@ -958,8 +957,9 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
958957
public async afterPrepareAllPlugins(projectData: IProjectData): Promise<void> {
959958
const projectRoot = this.getPlatformData(projectData).projectRoot;
960959
if (this.$fs.exists(this.$cocoapodsService.getProjectPodfilePath(projectRoot))) {
961-
const xcuserDataPath = path.join(this.getXcodeprojPath(projectData), "xcuserdata");
962-
const sharedDataPath = path.join(this.getXcodeprojPath(projectData), "xcshareddata");
960+
const xcodeProjPath = this.getXcodeprojPath(projectData);
961+
const xcuserDataPath = path.join(xcodeProjPath, "xcuserdata");
962+
const sharedDataPath = path.join(xcodeProjPath, "xcshareddata");
963963

964964
if (!this.$fs.exists(xcuserDataPath) && !this.$fs.exists(sharedDataPath)) {
965965
this.$logger.info("Creating project scheme...");
@@ -969,7 +969,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
969969
await this.$childProcess.exec(createSchemeRubyScript, { cwd: this.getPlatformData(projectData).projectRoot });
970970
}
971971

972-
await this.executePodInstall(projectData);
972+
await this.$cocoapodsService.executePodInstall(projectData, projectRoot, xcodeProjPath);
973973
}
974974
}
975975

@@ -1070,43 +1070,6 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
10701070
this.$fs.rename(path.join(fileRootLocation, oldFileName), path.join(fileRootLocation, newFileName));
10711071
}
10721072

1073-
private async executePodInstall(projectData: IProjectData): Promise<any> {
1074-
// Check availability
1075-
try {
1076-
await this.$childProcess.exec("which pod");
1077-
await this.$childProcess.exec("which xcodeproj");
1078-
} catch (e) {
1079-
this.$errors.failWithoutHelp("CocoaPods or ruby gem 'xcodeproj' is not installed. Run `sudo gem install cocoapods` and try again.");
1080-
}
1081-
1082-
await this.$xcprojService.verifyXcproj(true);
1083-
1084-
this.$logger.info("Installing pods...");
1085-
const podTool = this.$config.USE_POD_SANDBOX ? "sandbox-pod" : "pod";
1086-
const childProcess = await this.$childProcess.spawnFromEvent(podTool, ["install"], "close", { cwd: this.getPlatformData(projectData).projectRoot, stdio: ['pipe', process.stdout, 'pipe'] });
1087-
if (childProcess.stderr) {
1088-
const warnings = childProcess.stderr.match(/(\u001b\[(?:\d*;){0,5}\d*m[\s\S]+?\u001b\[(?:\d*;){0,5}\d*m)|(\[!\].*?\n)|(.*?warning.*)/gi);
1089-
_.each(warnings, (warning: string) => {
1090-
this.$logger.warnWithLabel(warning.replace("\n", ""));
1091-
});
1092-
1093-
let errors = childProcess.stderr;
1094-
_.each(warnings, warning => {
1095-
errors = errors.replace(warning, "");
1096-
});
1097-
1098-
if (errors.trim()) {
1099-
this.$errors.failWithoutHelp(`Pod install command failed. Error output: ${errors}`);
1100-
}
1101-
}
1102-
1103-
if ((await this.$xcprojService.getXcprojInfo()).shouldUseXcproj) {
1104-
await this.$childProcess.spawnFromEvent("xcproj", ["--project", this.getXcodeprojPath(projectData), "touch"], "close");
1105-
}
1106-
1107-
return childProcess;
1108-
}
1109-
11101073
private async prepareNativeSourceCode(pluginName: string, pluginPlatformsFolderPath: string, projectData: IProjectData): Promise<void> {
11111074
const project = this.createPbxProj(projectData);
11121075
const group = this.getRootGroup(pluginName, pluginPlatformsFolderPath);
@@ -1153,15 +1116,6 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
11531116
}
11541117
}
11551118

1156-
private async prepareCocoapods(pluginPlatformsFolderPath: string, pluginData: IPluginData, projectData: IProjectData, opts?: any): Promise<void> {
1157-
const projectRoot = this.getPlatformData(projectData).projectRoot;
1158-
await this.$cocoapodsService.applyPluginPodfileToProject(pluginData, projectData, projectRoot);
1159-
const pluginPodFilePath = path.join(pluginPlatformsFolderPath, "Podfile");
1160-
1161-
if (opts && opts.executePodInstall && this.$fs.exists(pluginPodFilePath)) {
1162-
await this.executePodInstall(projectData);
1163-
}
1164-
}
11651119
private removeNativeSourceCode(pluginPlatformsFolderPath: string, pluginData: IPluginData, projectData: IProjectData): void {
11661120
const project = this.createPbxProj(projectData);
11671121
const group = this.getRootGroup(pluginData.name, pluginPlatformsFolderPath);

test/cocoapods-service.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as yok from "../lib/common/yok";
22
import { assert } from "chai";
33
import { CocoaPodsService } from "../lib/services/cocoapods-service";
44
import { EOL } from "os";
5+
import { LoggerStub, ErrorsStub } from "./stubs";
56

67
interface IMergePodfileHooksTestCase {
78
input: string;
@@ -16,6 +17,11 @@ function createTestInjector(): IInjector {
1617

1718
testInjector.register("fs", {});
1819
testInjector.register("cocoapodsService", CocoaPodsService);
20+
testInjector.register("childProcess", {});
21+
testInjector.register("errors", ErrorsStub);
22+
testInjector.register("xcprojService", {});
23+
testInjector.register("logger", LoggerStub);
24+
testInjector.register("config", {});
1925

2026
return testInjector;
2127
}

0 commit comments

Comments
 (0)