11import { EOL } from "os" ;
2-
3- interface IRubyFunction {
4- functionName : string ;
5- functionParameters ?: string ;
6- }
2+ import * as path from "path" ;
3+ import { PluginNativeDirNames , PODFILE_NAME } from "../constants" ;
74
85export class CocoaPodsService implements ICocoaPodsService {
6+ private static PODFILE_POST_INSTALL_SECTION_NAME = "post_install" ;
7+ private static INSTALLER_BLOCK_PARAMETER_NAME = "installer" ;
8+
99 constructor ( private $fs : IFileSystem ) { }
1010
1111 public getPodfileHeader ( targetName : string ) : string {
@@ -16,20 +16,133 @@ export class CocoaPodsService implements ICocoaPodsService {
1616 return `${ EOL } end` ;
1717 }
1818
19- public mergePodfileHookContent ( hookName : string , pathToPodfile : string ) : void {
20- if ( ! this . $fs . exists ( pathToPodfile ) ) {
21- throw new Error ( `The Podfile ${ pathToPodfile } does not exist.` ) ;
19+ public getProjectPodfilePath ( projectRoot : string ) : string {
20+ return path . join ( projectRoot , PODFILE_NAME ) ;
21+ }
22+
23+ public async applyPluginPodfileToProject ( pluginData : IPluginData , projectData : IProjectData , nativeProjectPath : string ) : Promise < void > {
24+ const pluginPodFilePath = this . getPluginPodfilePath ( pluginData ) ;
25+ if ( ! this . $fs . exists ( pluginPodFilePath ) ) {
26+ return ;
27+ }
28+
29+ const { pluginPodfileContent, replacedFunctions } = this . buildPodfileContent ( pluginPodFilePath , pluginData . name ) ;
30+ const pathToProjectPodfile = this . getProjectPodfilePath ( nativeProjectPath ) ;
31+ const projectPodfileContent = this . $fs . exists ( pathToProjectPodfile ) ? this . $fs . readText ( pathToProjectPodfile ) . trim ( ) : "" ;
32+
33+ if ( projectPodfileContent . indexOf ( pluginPodfileContent ) === - 1 ) {
34+ // Remove old occurences of the plugin from the project's Podfile.
35+ this . removePluginPodfileFromProject ( pluginData , projectData , nativeProjectPath ) ;
36+ let finalPodfileContent = this . $fs . exists ( pathToProjectPodfile ) ? this . getPodfileContentWithoutTarget ( projectData , this . $fs . readText ( pathToProjectPodfile ) ) : "" ;
37+
38+ if ( pluginPodfileContent . indexOf ( CocoaPodsService . PODFILE_POST_INSTALL_SECTION_NAME ) !== - 1 ) {
39+ finalPodfileContent = this . addPostInstallHook ( replacedFunctions , finalPodfileContent , pluginPodfileContent ) ;
40+ }
41+
42+ finalPodfileContent = `${ pluginPodfileContent } ${ EOL } ${ finalPodfileContent } ` ;
43+ this . saveProjectPodfile ( projectData , finalPodfileContent , nativeProjectPath ) ;
44+ }
45+ }
46+
47+ public removePluginPodfileFromProject ( pluginData : IPluginData , projectData : IProjectData , projectRoot : string ) : void {
48+ const pluginPodfilePath = this . getPluginPodfilePath ( pluginData ) ;
49+
50+ if ( this . $fs . exists ( pluginPodfilePath ) && this . $fs . exists ( this . getProjectPodfilePath ( projectRoot ) ) ) {
51+ let projectPodFileContent = this . $fs . readText ( this . getProjectPodfilePath ( projectRoot ) ) ;
52+ // Remove the data between #Begin Podfile and #EndPodfile
53+ const regExpToRemove = new RegExp ( `${ this . getPluginPodfileHeader ( pluginPodfilePath ) } [\\s\\S]*?${ this . getPluginPodfileEnd ( ) } ` , "mg" ) ;
54+ projectPodFileContent = projectPodFileContent . replace ( regExpToRemove , "" ) ;
55+ projectPodFileContent = this . removePostInstallHook ( pluginData , projectPodFileContent ) ;
56+
57+ const defaultPodfileBeginning = this . getPodfileHeader ( projectData . projectName ) ;
58+ const defaultContentWithPostInstallHook = `${ defaultPodfileBeginning } ${ EOL } ${ this . getPostInstallHookHeader ( ) } end${ EOL } end` ;
59+ const defaultContentWithoutPostInstallHook = `${ defaultPodfileBeginning } end` ;
60+ const trimmedProjectPodFileContent = projectPodFileContent . trim ( ) ;
61+ if ( ! trimmedProjectPodFileContent || trimmedProjectPodFileContent === defaultContentWithPostInstallHook || trimmedProjectPodFileContent === defaultContentWithoutPostInstallHook ) {
62+ this . $fs . deleteFile ( this . getProjectPodfilePath ( projectRoot ) ) ;
63+ } else {
64+ this . $fs . writeFile ( this . getProjectPodfilePath ( projectRoot ) , projectPodFileContent ) ;
65+ }
2266 }
67+ }
68+
69+ private getPluginPodfilePath ( pluginData : IPluginData ) : string {
70+ const pluginPlatformsFolderPath = pluginData . pluginPlatformsFolderPath ( PluginNativeDirNames . iOS ) ;
71+ const pluginPodFilePath = path . join ( pluginPlatformsFolderPath , PODFILE_NAME ) ;
72+ return pluginPodFilePath ;
73+ }
2374
24- const podfileContent = this . $fs . readText ( pathToPodfile ) ;
75+ private addPostInstallHook ( replacedFunctions : IRubyFunction [ ] , finalPodfileContent : string , pluginPodfileContent : string ) : string {
76+ const postInstallHookStart = this . getPostInstallHookHeader ( ) ;
77+ let postInstallHookContent = "" ;
78+ _ . each ( replacedFunctions , rubyFunction => {
79+ let functionExecution = rubyFunction . functionName ;
80+ if ( rubyFunction . functionParameters && rubyFunction . functionParameters . length ) {
81+ functionExecution = `${ functionExecution } ${ CocoaPodsService . INSTALLER_BLOCK_PARAMETER_NAME } ` ;
82+ }
83+
84+ postInstallHookContent += ` ${ functionExecution } ${ EOL } ` ;
85+ } ) ;
86+
87+ if ( postInstallHookContent ) {
88+ const index = finalPodfileContent . indexOf ( postInstallHookStart ) ;
89+ if ( index !== - 1 ) {
90+ finalPodfileContent = finalPodfileContent . replace ( postInstallHookStart , `${ postInstallHookStart } ${ postInstallHookContent } ` ) ;
91+ } else {
92+ const postInstallHook = `${ postInstallHookStart } ${ postInstallHookContent } end` ;
93+ finalPodfileContent = `${ finalPodfileContent } ${ postInstallHook } ` ;
94+ }
95+ }
96+
97+ return finalPodfileContent ;
98+ }
99+
100+ private getPodfileContentWithoutTarget ( projectData : IProjectData , projectPodfileContent : string ) : string {
101+ const podFileHeader = this . getPodfileHeader ( projectData . projectName ) ;
102+
103+ if ( _ . startsWith ( projectPodfileContent , podFileHeader ) ) {
104+ projectPodfileContent = projectPodfileContent . substr ( podFileHeader . length ) ;
105+
106+ const podFileFooter = this . getPodfileFooter ( ) ;
107+ // Only remove the final end in case the file starts with the podFileHeader
108+ if ( _ . endsWith ( projectPodfileContent , podFileFooter ) ) {
109+ projectPodfileContent = projectPodfileContent . substr ( 0 , projectPodfileContent . length - podFileFooter . length ) ;
110+ }
111+ }
112+
113+ return projectPodfileContent . trim ( ) ;
114+ }
115+
116+ private saveProjectPodfile ( projectData : IProjectData , projectPodfileContent : string , projectRoot : string ) : void {
117+ projectPodfileContent = this . getPodfileContentWithoutTarget ( projectData , projectPodfileContent ) ;
118+ const podFileHeader = this . getPodfileHeader ( projectData . projectName ) ;
119+ const podFileFooter = this . getPodfileFooter ( ) ;
120+ const contentToWrite = `${ podFileHeader } ${ projectPodfileContent } ${ podFileFooter } ` ;
121+ const projectPodfilePath = this . getProjectPodfilePath ( projectRoot ) ;
122+ this . $fs . writeFile ( projectPodfilePath , contentToWrite ) ;
123+ }
124+
125+ private removePostInstallHook ( pluginData : IPluginData , projectPodFileContent : string ) : string {
126+ const regExp = new RegExp ( `^.*?${ this . getHookBasicFuncNameForPlugin ( CocoaPodsService . PODFILE_POST_INSTALL_SECTION_NAME , pluginData . name ) } .*?$\\r?\\n` , "gm" ) ;
127+ projectPodFileContent = projectPodFileContent . replace ( regExp , "" ) ;
128+ return projectPodFileContent ;
129+ }
130+
131+ private getHookBasicFuncNameForPlugin ( hookName : string , pluginName : string ) : string {
132+ // nativescript-hook and nativescript_hook should have different names, so replace all _ with ___ first and then replace all special symbols with _
133+ // This will lead to a clash in case plugins are called nativescript-hook and nativescript___hook
134+ const replacedPluginName = pluginName . replace ( / _ / g, "___" ) . replace ( / [ ^ A - Z a - z 0 - 9 _ ] / g, "_" ) ;
135+ return `${ hookName } ${ replacedPluginName } ` ;
136+ }
137+
138+ private replaceHookContent ( hookName : string , podfileContent : string , pluginName : string ) : { replacedContent : string , newFunctions : IRubyFunction [ ] } {
25139 const hookStart = `${ hookName } do` ;
26140
27141 const hookDefinitionRegExp = new RegExp ( `${ hookStart } *(\\|(\\w+)\\|)?` , "g" ) ;
28- let newFunctionNameIndex = 1 ;
29142 const newFunctions : IRubyFunction [ ] = [ ] ;
30143
31144 const replacedContent = podfileContent . replace ( hookDefinitionRegExp , ( substring : string , firstGroup : string , secondGroup : string , index : number ) : string => {
32- const newFunctionName = `${ hookName } ${ newFunctionNameIndex ++ } ` ;
145+ const newFunctionName = `${ this . getHookBasicFuncNameForPlugin ( hookName , pluginName ) } _ ${ newFunctions . length } ` ;
33146 let newDefinition = `def ${ newFunctionName } ` ;
34147
35148 const rubyFunction : IRubyFunction = { functionName : newFunctionName } ;
@@ -43,26 +156,31 @@ export class CocoaPodsService implements ICocoaPodsService {
43156 return newDefinition ;
44157 } ) ;
45158
46- if ( newFunctions . length > 1 ) {
47- // Execute all methods in the hook and pass the parameter to them.
48- const blokParameterName = "installer" ;
49- let mergedHookContent = `${ hookStart } |${ blokParameterName } |${ EOL } ` ;
159+ return { replacedContent, newFunctions } ;
160+ }
50161
51- _ . each ( newFunctions , ( rubyFunction : IRubyFunction ) => {
52- let functionExecution = rubyFunction . functionName ;
53- if ( rubyFunction . functionParameters && rubyFunction . functionParameters . length ) {
54- functionExecution = `${ functionExecution } ${ blokParameterName } ` ;
55- }
162+ private getPluginPodfileHeader ( pluginPodFilePath : string ) : string {
163+ return `# Begin Podfile - ${ pluginPodFilePath } ` ;
164+ }
56165
57- mergedHookContent = `${ mergedHookContent } ${ functionExecution } ${ EOL } ` ;
58- } ) ;
166+ private getPluginPodfileEnd ( ) : string {
167+ return `# End Podfile${ EOL } ` ;
168+ }
59169
60- mergedHookContent = `${ mergedHookContent } end` ;
170+ private getPostInstallHookHeader ( ) {
171+ return `${ CocoaPodsService . PODFILE_POST_INSTALL_SECTION_NAME } do |${ CocoaPodsService . INSTALLER_BLOCK_PARAMETER_NAME } |${ EOL } ` ;
172+ }
61173
62- const newPodfileContent = `${ replacedContent } ${ EOL } ${ mergedHookContent } ` ;
63- this . $fs . writeFile ( pathToPodfile , newPodfileContent ) ;
64- }
174+ private buildPodfileContent ( pluginPodFilePath : string , pluginName : string ) : { pluginPodfileContent : string , replacedFunctions : IRubyFunction [ ] } {
175+ const pluginPodfileContent = this . $fs . readText ( pluginPodFilePath ) ;
176+ const { replacedContent, newFunctions : replacedFunctions } = this . replaceHookContent ( CocoaPodsService . PODFILE_POST_INSTALL_SECTION_NAME , pluginPodfileContent , pluginName ) ;
177+
178+ return {
179+ pluginPodfileContent : `${ this . getPluginPodfileHeader ( pluginPodFilePath ) } ${ EOL } ${ replacedContent } ${ EOL } ${ this . getPluginPodfileEnd ( ) } ` ,
180+ replacedFunctions
181+ } ;
65182 }
183+
66184}
67185
68186$injector . register ( "cocoapodsService" , CocoaPodsService ) ;
0 commit comments