Skip to content

fix: Project's Podfile is regenerated incorrectly #3900

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 20, 2018

Conversation

rosen-vladimirov
Copy link
Contributor

In case multiple plugins have Podfile with post_install hook, CLI modifies the hook of each of them by renaming the hook's function and calling it in the single post_install that is allowed for Podfile (placed at the bottom of the project's Podfile). However, when some change in node_modules is detected, CLI processes all Podfiles again and tries to apply them to project's Podfile. The "apply" is check if the plugin's Podfile is already added to project's one and in case not - adding it again. Whenever all Podfiles are processed, the "afterPrepareAllPlugins" method checks the final project's Podfile and replaces the post_install hooks from all plugins with a new functions (by adding index to the name) and calls them inside a newly added post_install function.
This is not working as when CLI checks if a plugin's Podfile is already added to the project's one, it uses the original content of the plugin's Podfile, where the post_install hook is called post_install, while in the project's one it is renamed. So CLI always thinks that plugin's Podfile, which has post_install hook is not added to the project. CLI tries to add it again and messes the whole structure.

In order to fix the issue, apply the following logic:

  1. When a plugin has a Podfile, during prepare of the plugin read the content of this file. After that apply modifications over the file by replacing the post_install with a well known name - post_install<plugin_name>_<index>.
  2. Check if the replaced content is part of the project's Podfile. In case yes - do nothing.
  3. In case the replaced content is not part of the project's Podfile, it means that either we have never added this Podfile or its content has been changed. In order to handle both cases first remove the plugin's Podfile from the project's one - this includes removing the whole content between # Begin Podfile <podfile> and # End Podfile for this Podfile to be removed from the project's one and all post_install hooks with name that would have been used for this plugin to be removed. After that add the replaced content in the project's Podfile and call all post_install replaced functions in the project's Podfile's post_install hook.
  4. On afterPrepareAllPlugins do nothing with the Podfile, it is already processed.

This solution ensures the Podfile is correct after processing each plugin. The previous one relyed on the afterPrepareAllPlugins to fix the project's Podfile. Also, by using well known pattern for generating the post_install hooks, we ensure we can remove them from the final Podfile whenever is required.

PR Checklist

What is the current behavior?

Applying a change in a plugin's Podfile, when it has postinstall hook, causes the iOS build to fail.

What is the new behavior?

Applying a change in a plugin's Podfile, when it has postinstall hook, removes the old plugin's Podfile from the project and adds the new content.

Fixes #3549


const defaultPodfileBeginning = `use_frameworks!${EOL}${EOL}target "${projectData.projectName}" do${EOL}`;
const defaultContentWithPostInstallHook = `${defaultPodfileBeginning}${EOL}post_install do |installer|${EOL}end${EOL}end`;
const defaultContentWithoutPostInstallHooke = `${defaultPodfileBeginning}end`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo? shouldn't be defaultContentWithoutPostInstallHook?

}

public async applyPluginPodfileToProject(pluginData: IPluginData, projectData: IProjectData, nativeProjectPath: string): Promise<void> {
const pluginPodFilePath = this.getPathToPluginPodfile(pluginData);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following the concept this should be pluginPodfilePath (lowercase f)

return;
}

const { pluginPodFileContent, replacedFunctions } = this.buildPodfileContent(pluginPodFilePath, pluginData.name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pluginPodFileContent -> pluginPodfileContent


const { pluginPodFileContent, replacedFunctions } = this.buildPodfileContent(pluginPodFilePath, pluginData.name);
const pathToProjectPodfile = this.getProjectPodfilePath(nativeProjectPath);
const projectPodfileContent = this.$fs.exists(pathToProjectPodfile) ? this.$fs.readText(pathToProjectPodfile) : "";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we need to .trim() the content of file


const podfileContent = this.$fs.readText(pathToPodfile);
public removePluginPodfileFromProject(pluginData: IPluginData, projectData: IProjectData, projectRoot: string): void {
const pluginPodFilePath = this.getPathToPluginPodfile(pluginData);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to unify the following method names:

getPathToPluginPodfile()
getProjectPodfilePath

We can use

getPathToPluginPodfile
getPathToProjectPodfile

or

getPluginPodfilePath
getProjectPodfilePath

I'm voting for the second option 😸

projectPodFileContent = projectPodFileContent.replace(regExpToRemove, "");
projectPodFileContent = this.removePostInstallHook(pluginData, projectPodFileContent);

const defaultPodfileBeginning = `use_frameworks!${EOL}${EOL}target "${projectData.projectName}" do${EOL}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use here

const defaultPodfileBeginning  = this.getPodfileHeader(projectData.projectName)

private addPostInstallHook(replacedFunctions: IRubyFunction[], finalPodfileContent: string, pluginPodFileContent: string): string {
const hookStart = `${CocoaPodsService.PODFILE_POST_INSTALL_SECTION_NAME} do`;
const blokParameterName = "installer";
const postInstallHookStart = `${hookStart} |${blokParameterName}|${EOL}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we use a similar code here https://github.com/NativeScript/nativescript-cli/pull/3900/files#diff-e3190ab07db971b762e2395051443fc2R57, I'd suggest to extract the common part to separate method:

private getPostInstallHookHeader() {
    return `${CocoaPodsService.PODFILE_POST_INSTALL_SECTION_NAME} do |${CocoaPodsService.INSTALLER_BLOCK_PARAMETER_NAME}|${EOL}`
}
private addPostInstallHook(replacedFunctions: IRubyFunction[], finalPodfileContent: string, pluginPodFileContent: string): string {
    const postInstallHookStart = this.getPostInstallHookHeader();
}

}

private getHookBasicFuncNameForPlugin(hookName: string, pluginName: string): string {
return `${hookName}${pluginName.replace(/[^A-Za-z0-9]/g, "")}`;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed personally we need to change this to:

`${hookName}${pluginName.replace(/[^A-Za-z0-9]/g, "_")}`;

In case multiple plugins have Podfile with post_install hook, CLI modifies the hook of each of them by renaming the hook's function and calling it in the single post_install that is allowed for Podfile (placed at the bottom of the project's Podfile). However, when some change in node_modules is detected, CLI processes all Podfiles again and tries to apply them to project's Podfile. The "apply" is check if the plugin's Podfile is already added to project's one and in case not - adding it again. Whenever all Podfiles are processed, the "afterPrepareAllPlugins" method checks the final project's Podfile and replaces the post_install hooks from all plugins with a new functions (by adding index to the name) and calls them inside a newly added post_install function.
This is not working as when CLI checks if a plugin's Podfile is already added to the project's one, it uses the original content of the plugin's Podfile, where the post_install hook is called `post_install`, while in the project's one it is renamed. So CLI always thinks that plugin's Podfile, which has post_install hook is not added to the project. CLI tries to add it again and messes the whole structure.

In order to fix the issue, apply the following logic:
1. When a plugin has a Podfile, during prepare of the plugin read the content of this file. After that apply modifications over the file by replacing the post_install with a well known name - `post_install<plugin_name>_<index>`.
2. Check if the replaced content is part of the project's Podfile. In case yes - do nothing.
3. In case the replaced content is not part of the project's Podfile, it means that either we have never added this Podfile or its content has been changed. In order to handle both cases first remove the plugin's Podfile from the project's one - this includes removing the whole content between `# Begin Podfile <podfile>` and `# End Podfile` for this Podfile to be removed from the project's one and all post_install hooks with name that would have been used for this plugin to be removed. After that add the replaced content in the project's Podfile and call all post_install replaced functions in the project's Podfile's post_install hook.
4. On `afterPrepareAllPlugins` do nothing with the Podfile, it is already processed.

This solution ensures the Podfile is correct after processing each plugin. The previous one relyed on the `afterPrepareAllPlugins` to fix the project's Podfile. Also, by using well known pattern for generating the post_install hooks, we ensure we can remove them from the final Podfile whenever is required.
@rosen-vladimirov rosen-vladimirov force-pushed the vladimirov/fix-podfile-issues-2 branch from 73d1460 to 17aa4f4 Compare September 19, 2018 12:00
@rosen-vladimirov
Copy link
Contributor Author

run ci

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Podfile generation broken on livesync
2 participants