diff --git a/docs/dependencies.md b/docs/dependencies.md index 128b20582..6ce468e7d 100644 --- a/docs/dependencies.md +++ b/docs/dependencies.md @@ -56,7 +56,7 @@ The following settings are available on iOS and Android: ```ts type DependencyParamsIOST = { project?: string; - podspec?: string; + podspecPath?: string; sharedLibraries?: string[]; }; @@ -70,11 +70,11 @@ type DependencyParamsAndroidT = { #### platforms.ios.project -Custom path to `.xcodeproj` +Custom path to `.xcodeproj`. -#### platforms.ios.podspec +#### platforms.ios.podspecPath -Custom `podspec` name to use when auto-linking (without the file extension). Your `podspec` file must be located in the root of the dependency package. +Custom path to `.podspec` file to use when auto-linking. Example: `node_modules/react-native-module/ios/module.podspec`. #### platforms.ios.sharedLibraries diff --git a/docs/platforms.md b/docs/platforms.md index fa2f66d8e..8f85fbbd9 100644 --- a/docs/platforms.md +++ b/docs/platforms.md @@ -83,7 +83,7 @@ type ProjectConfigIOST = { folder: string; pbxprojPath: string; podfile: null; - podspec: null; + podspecPath: null; projectPath: string; projectName: string; libraryFolder: string; diff --git a/docs/projects.md b/docs/projects.md index 1d8cb92dc..caee753ba 100644 --- a/docs/projects.md +++ b/docs/projects.md @@ -81,6 +81,7 @@ type ProjectParamsAndroidT = { type ProjectParamsIOST = { project?: string; + podspecPath?: string; sharedLibraries?: string[]; libraryFolder?: string; plist: any[]; diff --git a/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap b/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap index dfc4d401c..36eb20609 100644 --- a/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap +++ b/packages/cli/src/tools/config/__tests__/__snapshots__/index-test.js.snap @@ -91,7 +91,7 @@ Object { "pbxprojPath": "<>/node_modules/react-native-test/ios/HelloWorld.xcodeproj/project.pbxproj", "plist": Array [], "podfile": null, - "podspec": null, + "podspecPath": null, "projectName": "HelloWorld.xcodeproj", "projectPath": "<>/node_modules/react-native-test/ios/HelloWorld.xcodeproj", "sharedLibraries": Array [], @@ -125,7 +125,7 @@ Object { "pbxprojPath": "<>/node_modules/react-native-foo/customLocation/customProject.xcodeproj/project.pbxproj", "plist": Array [], "podfile": null, - "podspec": null, + "podspecPath": null, "projectName": "customProject.xcodeproj", "projectPath": "<>/node_modules/react-native-foo/customLocation/customProject.xcodeproj", "sharedLibraries": Array [], @@ -164,7 +164,7 @@ Object { "pbxprojPath": "<>/node_modules/react-native-test/customLocation/customProject.xcodeproj/project.pbxproj", "plist": Array [], "podfile": null, - "podspec": "ReactNativeTest", + "podspecPath": "<>/node_modules/react-native-test/ReactNativeTest.podspec", "projectName": "customProject.xcodeproj", "projectPath": "<>/node_modules/react-native-test/customLocation/customProject.xcodeproj", "sharedLibraries": Array [], @@ -201,7 +201,7 @@ Object { "pbxprojPath": "<>/node_modules/react-native-test/ios/HelloWorld.xcodeproj/project.pbxproj", "plist": Array [], "podfile": null, - "podspec": null, + "podspecPath": null, "projectName": "HelloWorld.xcodeproj", "projectPath": "<>/node_modules/react-native-test/ios/HelloWorld.xcodeproj", "sharedLibraries": Array [], diff --git a/packages/cli/src/tools/config/schema.js b/packages/cli/src/tools/config/schema.js index 548a0f242..a6ee6d4a4 100644 --- a/packages/cli/src/tools/config/schema.js +++ b/packages/cli/src/tools/config/schema.js @@ -49,7 +49,7 @@ export const dependencyConfig = t ios: t .object({ project: t.string(), - podspec: t.string(), + podspecPath: t.string(), sharedLibraries: t.array().items(t.string()), libraryFolder: t.string(), }) @@ -113,7 +113,7 @@ export const projectConfig = t folder: t.string(), pbxprojPath: t.string(), podfile: t.string(), - podspec: t.string(), + podspecPath: t.string(), projectPath: t.string(), projectName: t.string(), libraryFolder: t.string(), diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 0df725e74..2eb120953 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -41,7 +41,7 @@ def use_native_modules!(root = "..", packages = nil) packages.each do |package_name, package| next unless package_config = package["platforms"]["ios"] - podspec_path = File.join(package["root"], "#{package_config["podspec"]}.podspec") + podspec_path = package_config["podspecPath"] spec = Pod::Specification.from_file(podspec_path) # We want to do a look up inside the current CocoaPods target @@ -57,7 +57,7 @@ def use_native_modules!(root = "..", packages = nil) existing_dep.name.split('/').first == spec.name end - pod spec.name, :path => package["root"] + pod spec.name, :path => File.dirname(podspec_path) if package_config["scriptPhases"] # Can be either an object, or an array of objects @@ -126,16 +126,16 @@ def pluralize(count) } @ios_package = ios_package = { - "root" => "/Users/grabbou/Repositories/WebViewDemoApp/node_modules/react", + "root" => "/root/app/node_modules/react", "platforms" => { "ios" => { - "podspec" => "React", + "podspecPath" => "/root/app/node_modules/react/React.podspec", }, "android" => nil, }, } @android_package = { - "root" => "/Users/grabbou/Repositories/WebViewDemoApp/node_modules/react-native-google-play-game-services", + "root" => "/root/app/node_modules/react-native-google-play-game-services", "platforms" => { "ios" => nil, "android" => { @@ -160,7 +160,7 @@ def pluralize(count) end Pod::Specification.singleton_class.send(:define_method, :from_file) do |podspec_path| - podspec_path.must_equal File.join(ios_package["root"], "#{ios_package["platforms"]["ios"]["podspec"]}.podspec") + podspec_path.must_equal ios_package["platforms"]["ios"]["podspecPath"] spec end diff --git a/packages/platform-ios/src/config/__tests__/findPodspecName-test.js b/packages/platform-ios/src/config/__tests__/findPodspec-test.js similarity index 70% rename from packages/platform-ios/src/config/__tests__/findPodspecName-test.js rename to packages/platform-ios/src/config/__tests__/findPodspec-test.js index 7a1c1600d..16b05b714 100644 --- a/packages/platform-ios/src/config/__tests__/findPodspecName-test.js +++ b/packages/platform-ios/src/config/__tests__/findPodspec-test.js @@ -4,11 +4,10 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format - * @emails oncall+javascript_foundation + * @flow */ -import findPodspecName from '../findPodspecName'; +import findPodspec from '../findPodspec'; import * as projects from '../__fixtures__/projects'; jest.mock('path'); @@ -16,18 +15,21 @@ jest.mock('fs'); const fs = require('fs'); -describe('ios::findPodspecName', () => { +describe('ios::findPodspec', () => { it('returns null if there is not podspec file', () => { + // $FlowFixMe fs.__setMockFilesystem(projects.flat); - expect(findPodspecName('')).toBeNull(); + expect(findPodspec('')).toBeNull(); }); it('returns podspec name if only one exists', () => { + // $FlowFixMe fs.__setMockFilesystem(projects.withPods.ios); - expect(findPodspecName('/')).toBe('TestPod'); + expect(findPodspec('/')).toBe('/TestPod.podspec'); }); it('returns podspec name that match packet directory', () => { + // $FlowFixMe fs.__setMockFilesystem({ user: { PacketName: { @@ -36,10 +38,13 @@ describe('ios::findPodspecName', () => { }, }, }); - expect(findPodspecName('/user/PacketName')).toBe('PacketName'); + expect(findPodspec('/user/PacketName')).toBe( + '/user/PacketName/PacketName.podspec', + ); }); it('returns first podspec name if not match in directory', () => { + // $FlowFixMe fs.__setMockFilesystem({ user: { packet: { @@ -48,6 +53,6 @@ describe('ios::findPodspecName', () => { }, }, }); - expect(findPodspecName('/user/packet')).toBe('Another'); + expect(findPodspec('/user/packet')).toBe('/user/packet/Another.podspec'); }); }); diff --git a/packages/platform-ios/src/config/findPodspec.js b/packages/platform-ios/src/config/findPodspec.js new file mode 100644 index 000000000..30ab98d00 --- /dev/null +++ b/packages/platform-ios/src/config/findPodspec.js @@ -0,0 +1,21 @@ +/** + * @flow + */ + +import glob from 'glob'; +import path from 'path'; + +export default function findPodspec(folder: string): string | null { + const podspecs = glob.sync('*.podspec', {cwd: folder}); + + if (podspecs.length === 0) { + return null; + } + + const packagePodspec = path.basename(folder) + '.podspec'; + const podspecFile = podspecs.includes(packagePodspec) + ? packagePodspec + : podspecs[0]; + + return path.join(folder, podspecFile); +} diff --git a/packages/platform-ios/src/config/findPodspecName.js b/packages/platform-ios/src/config/findPodspecName.js deleted file mode 100644 index eb14ba8b5..000000000 --- a/packages/platform-ios/src/config/findPodspecName.js +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * @format - * @flow - */ - -import glob from 'glob'; -import path from 'path'; - -export default function findPodspecName(folder: string): string | null { - const podspecs = glob.sync('*.podspec', {cwd: folder}); - let podspecFile = null; - if (podspecs.length === 0) { - return null; - } - if (podspecs.length === 1) { - podspecFile = podspecs[0]; - } else { - const folderParts = folder.split(path.sep); - const currentFolder = folderParts[folderParts.length - 1]; - const toSelect = podspecs.indexOf(`${currentFolder}.podspec`); - if (toSelect === -1) { - podspecFile = podspecs[0]; - } else { - podspecFile = podspecs[toSelect]; - } - } - - return podspecFile.replace('.podspec', ''); -} diff --git a/packages/platform-ios/src/config/getPodspecName.js b/packages/platform-ios/src/config/getPodspecName.js new file mode 100644 index 000000000..19fc35fc9 --- /dev/null +++ b/packages/platform-ios/src/config/getPodspecName.js @@ -0,0 +1,13 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ +import path from 'path'; + +export default function getPodspecName(podspecFile: string) { + return path.basename(podspecFile).replace(/\.podspec$/, ''); +} diff --git a/packages/platform-ios/src/config/index.js b/packages/platform-ios/src/config/index.js index 258d4afb1..a6f7b4855 100644 --- a/packages/platform-ios/src/config/index.js +++ b/packages/platform-ios/src/config/index.js @@ -11,7 +11,7 @@ import path from 'path'; import findProject from './findProject'; import findPodfilePath from './findPodfilePath'; -import findPodspecName from './findPodspecName'; +import findPodspec from './findPodspec'; import type {UserConfigT} from 'types'; /** @@ -47,13 +47,19 @@ export function projectConfig( } const projectPath = path.join(folder, project); + const sourceDir = path.dirname(projectPath); return { - sourceDir: path.dirname(projectPath), + sourceDir, folder, pbxprojPath: path.join(projectPath, 'project.pbxproj'), podfile: findPodfilePath(projectPath), - podspec: userConfig.podspec || findPodspecName(folder), + podspecPath: + userConfig.podspecPath || + // podspecs are usually placed in the root dir of the library or in the + // iOS project path + findPodspec(folder) || + findPodspec(sourceDir), projectPath, projectName: path.basename(projectPath), libraryFolder: userConfig.libraryFolder || 'Libraries', diff --git a/packages/platform-ios/src/link-pods/__tests__/isInstalled-test.js b/packages/platform-ios/src/link-pods/__tests__/isInstalled-test.js index 0f66648f6..2b606b104 100644 --- a/packages/platform-ios/src/link-pods/__tests__/isInstalled-test.js +++ b/packages/platform-ios/src/link-pods/__tests__/isInstalled-test.js @@ -17,19 +17,19 @@ const PODFILES_PATH = path.join(__dirname, '../__fixtures__/'); describe('pods::isInstalled', () => { it('returns false if pod is missing', () => { const project = {podfile: path.join(PODFILES_PATH, 'PodfileSimple')}; - const podspecName = {podspec: 'NotExisting'}; + const podspecName = {podspecPath: '/path/NotExisting'}; expect(isInstalled(project, podspecName)).toBe(false); }); it('returns true for existing pod with version number', () => { const project = {podfile: path.join(PODFILES_PATH, 'PodfileSimple')}; - const podspecName = {podspec: 'TestPod'}; + const podspecName = {podspecPath: '/path/TestPod.podspec'}; expect(isInstalled(project, podspecName)).toBe(true); }); it('returns true for existing pod with path', () => { const project = {podfile: path.join(PODFILES_PATH, 'PodfileWithTarget')}; - const podspecName = {podspec: 'Yoga'}; + const podspecName = {podspecPath: '/path/Yoga.podspec'}; expect(isInstalled(project, podspecName)).toBe(true); }); @@ -37,7 +37,7 @@ describe('pods::isInstalled', () => { const project = { podfile: path.join(PODFILES_PATH, 'PodfileWithFunction'), }; - const podspecName = {podspec: 'React'}; + const podspecName = {podspecPath: '/path/React.podspec'}; expect(isInstalled(project, podspecName)).toBe(true); }); }); diff --git a/packages/platform-ios/src/link-pods/addPodEntry.js b/packages/platform-ios/src/link-pods/addPodEntry.js index d22d088ba..86d327feb 100644 --- a/packages/platform-ios/src/link-pods/addPodEntry.js +++ b/packages/platform-ios/src/link-pods/addPodEntry.js @@ -4,18 +4,22 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import {logger} from '@react-native-community/cli-tools'; +import getPodspecName from '../config/getPodspecName'; export default function addPodEntry( - podLines, - linesToAddEntry, - podName, - nodePath, + podLines: Array, + linesToAddEntry?: + | Array<{line: number, indentation: number}> + | {line: number, indentation: number}, + podspecPath: string, + nodeModulePath: string, ) { - const newEntry = `pod '${podName}', :path => '../node_modules/${nodePath}'\n`; + const podName = getPodspecName(podspecPath); + const newEntry = `pod '${podName}', :path => '../node_modules/${nodeModulePath}'\n`; if (!linesToAddEntry) { return; diff --git a/packages/platform-ios/src/link-pods/findMarkedLinesInPodfile.js b/packages/platform-ios/src/link-pods/findMarkedLinesInPodfile.js index 05033817a..13cae2c14 100644 --- a/packages/platform-ios/src/link-pods/findMarkedLinesInPodfile.js +++ b/packages/platform-ios/src/link-pods/findMarkedLinesInPodfile.js @@ -4,12 +4,12 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ export const MARKER_TEXT = '# Add new pods below this line'; -export default function findMarkedLinesInPodfile(podLines) { +export default function findMarkedLinesInPodfile(podLines: Array) { const result = []; for (let i = 0, len = podLines.length; i < len; i++) { if (podLines[i].includes(MARKER_TEXT)) { diff --git a/packages/platform-ios/src/link-pods/isInstalled.js b/packages/platform-ios/src/link-pods/isInstalled.js index e68059616..d925a5592 100644 --- a/packages/platform-ios/src/link-pods/isInstalled.js +++ b/packages/platform-ios/src/link-pods/isInstalled.js @@ -8,6 +8,7 @@ */ import readPodfile from './readPodfile'; +import getPodspecName from '../config/getPodspecName'; export default function isInstalled(iOSProject, dependencyConfig) { if (!iOSProject.podfile) { @@ -15,7 +16,7 @@ export default function isInstalled(iOSProject, dependencyConfig) { } // match line with pod declaration: pod 'dependencyPodName' (other possible parameters of pod are ignored) const dependencyRegExp = new RegExp( - `pod\\s+('|")${dependencyConfig.podspec}('|")`, + `pod\\s+('|")${getPodspecName(dependencyConfig.podspecPath)}('|")`, 'g', ); const podLines = readPodfile(iOSProject.podfile); diff --git a/packages/platform-ios/src/link-pods/registerNativeModule.js b/packages/platform-ios/src/link-pods/registerNativeModule.js index 7a4bcd130..4cbb21ba6 100644 --- a/packages/platform-ios/src/link-pods/registerNativeModule.js +++ b/packages/platform-ios/src/link-pods/registerNativeModule.js @@ -4,11 +4,11 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import chalk from 'chalk'; import {CLIError} from '@react-native-community/cli-tools'; - +import type {ProjectConfigIOST} from 'types'; import readPodfile from './readPodfile'; import findPodTargetLine from './findPodTargetLine'; import findLineToAddPod from './findLineToAddPod'; @@ -19,13 +19,13 @@ import addPodEntry from './addPodEntry'; import savePodFile from './savePodFile'; export default function registerNativeModulePods( - name, - dependencyConfig, - iOSProject, + name: string, + podspecPath: string, + iOSProject: ProjectConfigIOST, ) { const podLines = readPodfile(iOSProject.podfile); const linesToAddEntry = getLinesToAddEntry(podLines, iOSProject); - addPodEntry(podLines, linesToAddEntry, dependencyConfig.podspec, name); + addPodEntry(podLines, linesToAddEntry, podspecPath, name); savePodFile(iOSProject.podfile, podLines); } diff --git a/packages/platform-ios/src/link-pods/removePodEntry.js b/packages/platform-ios/src/link-pods/removePodEntry.js index 75849636d..7ee8f9eea 100644 --- a/packages/platform-ios/src/link-pods/removePodEntry.js +++ b/packages/platform-ios/src/link-pods/removePodEntry.js @@ -8,8 +8,10 @@ */ import {logger} from '@react-native-community/cli-tools'; +import getPodspecName from '../config/getPodspecName'; -export default function removePodEntry(podfileContent, podName) { +export default function removePodEntry(podfileContent, podspecPath) { + const podName = getPodspecName(podspecPath); // this regex should catch line(s) with full pod definition, like: pod 'podname', :path => '../node_modules/podname', :subspecs => ['Sub2', 'Sub1'] const podRegex = new RegExp( `\\n( |\\t)*pod\\s+("|')${podName}("|')(,\\s*(:[a-z]+\\s*=>)?\\s*(("|').*?("|')|\\[[\\s\\S]*?\\]))*\\n`, diff --git a/packages/platform-ios/src/link-pods/unregisterNativeModule.js b/packages/platform-ios/src/link-pods/unregisterNativeModule.js index fc485fc93..6ac7ca71d 100644 --- a/packages/platform-ios/src/link-pods/unregisterNativeModule.js +++ b/packages/platform-ios/src/link-pods/unregisterNativeModule.js @@ -16,7 +16,7 @@ import {logger} from '@react-native-community/cli-tools'; */ export default function unregisterNativeModule(dependencyConfig, iOSProject) { const podContent = fs.readFileSync(iOSProject.podfile, 'utf8'); - const removed = removePodEntry(podContent, dependencyConfig.podspec); + const removed = removePodEntry(podContent, dependencyConfig.podspecPath); logger.debug(`Writing changes to ${iOSProject.podfile}`); fs.writeFileSync(iOSProject.podfile, removed); } diff --git a/packages/platform-ios/src/link/common/registerNativeModule.js b/packages/platform-ios/src/link/common/registerNativeModule.js index cefca1dfa..041e60cb8 100644 --- a/packages/platform-ios/src/link/common/registerNativeModule.js +++ b/packages/platform-ios/src/link/common/registerNativeModule.js @@ -4,20 +4,21 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ +import type {DependencyConfigIOST, ProjectConfigIOST} from 'types'; import registerDependencyIOS from '../registerNativeModule'; import registerDependencyPods from '../../link-pods/registerNativeModule'; export default function registerNativeModule( - name, - dependencyConfig, - params, - projectConfig, + name: string, + dependencyConfig: DependencyConfigIOST, + params?: any, + projectConfig: ProjectConfigIOST, ) { - if (projectConfig.podfile && dependencyConfig.podspec) { - registerDependencyPods(name, dependencyConfig, projectConfig); + if (projectConfig.podfile && dependencyConfig.podspecPath) { + registerDependencyPods(name, dependencyConfig.podspecPath, projectConfig); } else { registerDependencyIOS(dependencyConfig, projectConfig); } diff --git a/packages/platform-ios/src/link/registerNativeModule.js b/packages/platform-ios/src/link/registerNativeModule.js index 2583d60fb..698f89139 100644 --- a/packages/platform-ios/src/link/registerNativeModule.js +++ b/packages/platform-ios/src/link/registerNativeModule.js @@ -4,14 +4,14 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @format + * @flow */ import xcode from 'xcode'; import fs from 'fs'; import path from 'path'; import {isEmpty} from 'lodash'; - +import type {DependencyConfigIOST, ProjectConfigIOST} from 'types'; import addToHeaderSearchPaths from './addToHeaderSearchPaths'; import getHeadersInFolder from './getHeadersInFolder'; import getHeaderSearchPath from './getHeaderSearchPath'; @@ -30,8 +30,8 @@ import {logger} from '@react-native-community/cli-tools'; * If library is already linked, this action is a no-op. */ export default function registerNativeModuleIOS( - dependencyConfig, - projectConfig, + dependencyConfig: DependencyConfigIOST, + projectConfig: ProjectConfigIOST, ) { logger.debug(`Reading ${projectConfig.pbxprojPath}`); const project = xcode.project(projectConfig.pbxprojPath).parseSync(); diff --git a/types/index.js b/types/index.js index c2c6d6523..cfd7a2940 100644 --- a/types/index.js +++ b/types/index.js @@ -66,7 +66,7 @@ type ProjectParamsAndroidT = { */ type ProjectParamsIOST = { project?: string, - podspec?: string, + podspecPath?: string, sharedLibraries?: string[], libraryFolder?: string, plist: any[], @@ -222,14 +222,14 @@ export type ProjectConfigIOST = { folder: string, pbxprojPath: string, podfile: null, - podspec: null | string, + podspecPath: null | string, projectPath: string, projectName: string, libraryFolder: string, sharedLibraries: Array, plist: Array, }; -type DependencyConfigIOST = ProjectConfigIOST; +export type DependencyConfigIOST = ProjectConfigIOST; type ProjectConfigAndroidT = { sourceDir: string, isFlat: boolean,