Skip to content

Commit 9d6d0fa

Browse files
Merge pull request #2288 from NativeScript/milanov/appbuilder-2.3.0-update-with-podfile-merge
Merge post_install hooks in Podfile
2 parents 90558d3 + 3a331e7 commit 9d6d0fa

File tree

4 files changed

+244
-1
lines changed

4 files changed

+244
-1
lines changed

lib/definitions/project.d.ts

+8
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,12 @@ interface ICocoaPodsService {
122122
* @return {string} The footer which needs to be placed at the end of a Podfile.
123123
*/
124124
getPodfileFooter(): string;
125+
126+
/**
127+
* Merges the content of hooks with the provided name if there are more than one hooks with this name in the Podfile.
128+
* @param {string} hookName The name of the hook.
129+
* @param {string} pathToPodfile The path to the Podfile.
130+
* @return {IFuture<void>}
131+
*/
132+
mergePodfileHookContent(sectionName: string, pathToPodfile: string): IFuture<void>
125133
}

lib/services/cocoapods-service.ts

+57
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,70 @@
11
import {EOL} from "os";
22

3+
interface IRubyFunction {
4+
functionName: string;
5+
functionParameters?: string;
6+
}
7+
38
export class CocoaPodsService implements ICocoaPodsService {
9+
constructor(private $fs: IFileSystem) { }
10+
411
public getPodfileHeader(targetName: string): string {
512
return `use_frameworks!${EOL}${EOL}target "${targetName}" do${EOL}`;
613
}
714

815
public getPodfileFooter(): string {
916
return `${EOL}end`;
1017
}
18+
19+
public mergePodfileHookContent(hookName: string, pathToPodfile: string): IFuture<void> {
20+
return (() => {
21+
if (!this.$fs.exists(pathToPodfile).wait()) {
22+
throw new Error(`The Podfile ${pathToPodfile} does not exist.`);
23+
}
24+
25+
let podfileContent = this.$fs.readText(pathToPodfile).wait();
26+
let hookStart = `${hookName} do`;
27+
28+
let hookDefinitionRegExp = new RegExp(`${hookStart} *(\\|(\\w+)\\|)?`, "g");
29+
let newFunctionNameIndex = 1;
30+
let newFunctions: IRubyFunction[] = [];
31+
32+
let replacedContent = podfileContent.replace(hookDefinitionRegExp, (substring: string, firstGroup: string, secondGroup: string, index: number): string => {
33+
let newFunctionName = `${hookName}${newFunctionNameIndex++}`;
34+
let newDefinition = `def ${newFunctionName}`;
35+
36+
let rubyFunction: IRubyFunction = { functionName: newFunctionName };
37+
// firstGroup is the block parameter, secondGroup is the block parameter name.
38+
if (firstGroup && secondGroup) {
39+
newDefinition = `${newDefinition} (${secondGroup})`;
40+
rubyFunction.functionParameters = secondGroup;
41+
}
42+
43+
newFunctions.push(rubyFunction);
44+
return newDefinition;
45+
});
46+
47+
if (newFunctions.length > 1) {
48+
// Execute all methods in the hook and pass the parameter to them.
49+
let blokParameterName = "installer";
50+
let mergedHookContent = `${hookStart} |${blokParameterName}|${EOL}`;
51+
52+
_.each(newFunctions, (rubyFunction: IRubyFunction) => {
53+
let functionExecution = rubyFunction.functionName;
54+
if (rubyFunction.functionParameters && rubyFunction.functionParameters.length) {
55+
functionExecution = `${functionExecution} ${blokParameterName}`;
56+
}
57+
58+
mergedHookContent = `${mergedHookContent} ${functionExecution}${EOL}`;
59+
});
60+
61+
mergedHookContent = `${mergedHookContent}end`;
62+
63+
let newPodfileContent = `${replacedContent}${EOL}${mergedHookContent}`;
64+
this.$fs.writeFile(pathToPodfile, newPodfileContent).wait();
65+
}
66+
}).future<void>()();
67+
}
1168
}
1269

1370
$injector.register("cocoapodsService", CocoaPodsService);

lib/services/ios-project-service.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ We will now place an empty obsolete compatability white screen LauncScreen.xib f
782782

783783
let firstPostInstallIndex = projectPodfileContent.indexOf(IOSProjectService.PODFILE_POST_INSTALL_SECTION_NAME);
784784
if (firstPostInstallIndex !== -1 && firstPostInstallIndex !== projectPodfileContent.lastIndexOf(IOSProjectService.PODFILE_POST_INSTALL_SECTION_NAME)) {
785-
this.$logger.warn(`Podfile contains more than one post_install sections. You need to open ${this.projectPodFilePath} file and manually resolve this issue.`);
785+
this.$cocoapodsService.mergePodfileHookContent(IOSProjectService.PODFILE_POST_INSTALL_SECTION_NAME, this.projectPodFilePath).wait();
786786
}
787787

788788
let xcuserDataPath = path.join(this.xcodeprojPath, "xcuserdata");

test/cocoapods-service.ts

+178
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import * as yok from "../lib/common/yok";
2+
import {assert} from "chai";
3+
import {CocoaPodsService} from "../lib/services/cocoapods-service";
4+
import {EOL} from "os";
5+
import Future = require("fibers/future");
6+
7+
interface IMergePodfileHooksTestCase {
8+
input: string;
9+
output: string;
10+
testCaseDescription: string;
11+
}
12+
13+
function createTestInjector(): IInjector {
14+
let testInjector: IInjector = new yok.Yok();
15+
16+
testInjector.register("fs", {});
17+
testInjector.register("cocoapodsService", CocoaPodsService);
18+
19+
return testInjector;
20+
}
21+
22+
// The newline characters should be replaced with EOL because on Windows the EOL is \r\n
23+
// but the character which is placed in `` for newline is only \n
24+
// if we do not replace the newline characters the tests will pass only on linux and mac.
25+
function changeNewLineCharacter(input: string): string {
26+
return input ? input.replace(/\r?\n/g, EOL) : input;
27+
}
28+
29+
describe("Cocoapods service", () => {
30+
describe("merge Podfile hooks", () => {
31+
let testInjector: IInjector;
32+
let cocoapodsService: ICocoaPodsService;
33+
let newPodfileContent: string;
34+
35+
let mockFileSystem = (injector: IInjector, podfileContent: string): void => {
36+
let fs: IFileSystem = injector.resolve("fs");
37+
38+
fs.exists = () => Future.fromResult(true);
39+
fs.readText = () => Future.fromResult(podfileContent);
40+
fs.writeFile = (pathToFile: string, content: any) => {
41+
newPodfileContent = content;
42+
return Future.fromResult();
43+
};
44+
};
45+
46+
let testCaces: IMergePodfileHooksTestCase[] = [
47+
{
48+
input: `
49+
target 'MyApp' do
50+
pod 'GoogleAnalytics', '~> 3.1'
51+
target 'MyAppTests' do
52+
inherit! :search_paths
53+
pod 'OCMock', '~> 2.0.1'
54+
end
55+
end
56+
57+
post_install do |installer|
58+
installer.pods_project.targets.each do |target|
59+
puts target.name
60+
end
61+
end
62+
post_install do |installer|
63+
installer.pods_project.targets.each do |target|
64+
puts target.name
65+
end
66+
end
67+
post_install do |installer|
68+
installer.pods_project.targets.each do |target|
69+
puts target.name
70+
end
71+
end`,
72+
output: `
73+
target 'MyApp' do
74+
pod 'GoogleAnalytics', '~> 3.1'
75+
target 'MyAppTests' do
76+
inherit! :search_paths
77+
pod 'OCMock', '~> 2.0.1'
78+
end
79+
end
80+
81+
def post_install1 (installer)
82+
installer.pods_project.targets.each do |target|
83+
puts target.name
84+
end
85+
end
86+
def post_install2 (installer)
87+
installer.pods_project.targets.each do |target|
88+
puts target.name
89+
end
90+
end
91+
def post_install3 (installer)
92+
installer.pods_project.targets.each do |target|
93+
puts target.name
94+
end
95+
end
96+
post_install do |installer|
97+
post_install1 installer
98+
post_install2 installer
99+
post_install3 installer
100+
end`,
101+
testCaseDescription: "should merge more than one hooks with block parameter correctly."
102+
}, {
103+
input: `
104+
target 'MyApp' do
105+
pod 'GoogleAnalytics', '~> 3.1'
106+
target 'MyAppTests' do
107+
inherit! :search_paths
108+
pod 'OCMock', '~> 2.0.1'
109+
end
110+
111+
post_install do |installer_representation|
112+
installer_representation.pods_project.targets.each do |target|
113+
puts target.name
114+
end
115+
end
116+
post_install do
117+
puts "Hello World!"
118+
end
119+
end`,
120+
output: `
121+
target 'MyApp' do
122+
pod 'GoogleAnalytics', '~> 3.1'
123+
target 'MyAppTests' do
124+
inherit! :search_paths
125+
pod 'OCMock', '~> 2.0.1'
126+
end
127+
128+
def post_install1 (installer_representation)
129+
installer_representation.pods_project.targets.each do |target|
130+
puts target.name
131+
end
132+
end
133+
def post_install2
134+
puts "Hello World!"
135+
end
136+
end
137+
post_install do |installer|
138+
post_install1 installer
139+
post_install2
140+
end`,
141+
testCaseDescription: "should merge more than one hooks with and without block parameter correctly."
142+
}, {
143+
input: `
144+
target 'MyApp' do
145+
pod 'GoogleAnalytics', '~> 3.1'
146+
target 'MyAppTests' do
147+
inherit! :search_paths
148+
pod 'OCMock', '~> 2.0.1'
149+
end
150+
end
151+
152+
post_install do |installer|
153+
installer.pods_project.targets.each do |target|
154+
puts target.name
155+
end
156+
end`,
157+
output: null,
158+
testCaseDescription: "should not change the Podfile when there is only one hook."
159+
}
160+
];
161+
162+
beforeEach(() => {
163+
testInjector = createTestInjector();
164+
cocoapodsService = testInjector.resolve("cocoapodsService");
165+
newPodfileContent = null;
166+
});
167+
168+
_.each(testCaces, (testCase: IMergePodfileHooksTestCase) => {
169+
it(testCase.testCaseDescription, () => {
170+
mockFileSystem(testInjector, testCase.input);
171+
172+
cocoapodsService.mergePodfileHookContent("post_install", "").wait();
173+
174+
assert.deepEqual(changeNewLineCharacter(newPodfileContent), changeNewLineCharacter(testCase.output));
175+
});
176+
});
177+
});
178+
});

0 commit comments

Comments
 (0)