From b3b09efe12a4aa618e8e3c89e640f90189148a65 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 20:30:02 +0200 Subject: [PATCH 01/43] Improve handling of files in monorepo --- packages/platform-ios/native_modules.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index d42cc26b1..a34a8d55e 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -5,24 +5,23 @@ # require 'pathname' -def use_native_modules!(root = "..", config = nil) +def use_native_modules!(config = nil) if (!config) json = [] - # Make sure `react-native config` is ran from your project root - Dir.chdir(root) do - IO.popen("./node_modules/.bin/react-native config") do |data| - while line = data.gets - json << line - end + # @todo: Do not use Yarn here, but find path dynamically + IO.popen("yarn run --silent react-native config") do |data| + while line = data.gets + json << line end end config = JSON.parse(json.join("\n")) end + project_root = Pathname.new(config["project"]["ios"]["sourceDir"]) + packages = config["dependencies"] - config_root = config["root"] found_pods = [] packages.each do |package_name, package| @@ -57,10 +56,10 @@ def use_native_modules!(root = "..", config = nil) end podspec_dir_path = Pathname.new(File.dirname(podspec_path)) - project_root = Pathname.new(config_root) + relative_path = podspec_dir_path.relative_path_from project_root - pod spec.name, :path => File.join(root, relative_path) + pod spec.name, :path => relative_path if package_config["scriptPhases"] # Can be either an object, or an array of objects From 440f1669610540f8aa25df643dc0a9eb80a60ae6 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 20:56:17 +0200 Subject: [PATCH 02/43] Fix tests with my poor Ruby haha --- packages/platform-ios/native_modules.rb | 28 ++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index a34a8d55e..358125c09 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -128,7 +128,6 @@ def pluralize(count) "execution_position" => "before_compile", "input" => "string" } - @ios_package = ios_package = { "root" => "/root/app/node_modules/react", "platforms" => { @@ -147,8 +146,13 @@ def pluralize(count) }, } } + @project = { + "ios" => { + "sourceDir": "/root/app" + } + } @config = { - "root" => "/root/app", + "project" => project, "dependencies" => { "ios-dep" => @ios_package, "android-dep" => @android_package @@ -166,7 +170,7 @@ def pluralize(count) spec.singleton_class.send(:define_method, :name) { "ios-dep" } podfile.singleton_class.send(:define_method, :use_native_modules) do |path, config| - use_native_modules!('..', config) + use_native_modules!(config) end Pod::Specification.singleton_class.send(:define_method, :from_file) do |podspec_path| @@ -196,7 +200,7 @@ def pluralize(count) end it "activates iOS pods" do - @podfile.use_native_modules('..', @config) + @podfile.use_native_modules(@config) @activated_pods.must_equal [{ name: "ios-dep", options: { path: "../node_modules/react" } @@ -207,7 +211,7 @@ def pluralize(count) activated_pod = Object.new activated_pod.singleton_class.send(:define_method, :name) { "ios-dep" } @current_target_definition_dependencies << activated_pod - @podfile.use_native_modules('..', @config) + @podfile.use_native_modules(@config) @activated_pods.must_equal [] end @@ -215,15 +219,15 @@ def pluralize(count) activated_pod = Object.new activated_pod.singleton_class.send(:define_method, :name) { "ios-dep/foo/bar" } @current_target_definition_dependencies << activated_pod - @podfile.use_native_modules('..', @config) + @podfile.use_native_modules(@config) @activated_pods.must_equal [] end it "prints out the native module pods that were found" do - @podfile.use_native_modules('..', { "root" => "/root/app", "dependencies" => {} }) - @podfile.use_native_modules('..', { "root" => "/root/app", "dependencies" => { "pkg-1" => @ios_package }}) - @podfile.use_native_modules('..', { - "root" => "/root/app", "dependencies" => { "pkg-1" => @ios_package, "pkg-2" => @ios_package } + @podfile.use_native_modules({ "project" => project, "dependencies" => {} }) + @podfile.use_native_modules({ "project" => project, "dependencies" => { "pkg-1" => @ios_package }}) + @podfile.use_native_modules({ + "project" => project, "dependencies" => { "pkg-1" => @ios_package, "pkg-2" => @ios_package } }) @printed_messages.must_equal [ "Detected React Native module pod for ios-dep", @@ -234,7 +238,7 @@ def pluralize(count) describe "concerning script_phases" do it "uses the options directly" do @config["dependencies"]["ios-dep"]["platforms"]["ios"]["scriptPhases"] = [@script_phase] - @podfile.use_native_modules('..', @config) + @podfile.use_native_modules(@config) @added_scripts.must_equal [{ :script => "123", :name => "My Name", @@ -252,7 +256,7 @@ def pluralize(count) file_read_mock.expect(:call, "contents from file", [File.join(@ios_package["root"], "some_shell_script.sh")]) File.stub(:read, file_read_mock) do - @podfile.use_native_modules('..', @config) + @podfile.use_native_modules(@config) end @added_scripts.must_equal [{ From 1ffc0c25ac4b697fc92fbaaf6df7b1bec156c4f2 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 20:57:50 +0200 Subject: [PATCH 03/43] Remove note about monorepo from the docs --- docs/autolinking.md | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/docs/autolinking.md b/docs/autolinking.md index 99cf2b666..cfc03423b 100644 --- a/docs/autolinking.md +++ b/docs/autolinking.md @@ -36,28 +36,6 @@ The implementation ensures that a library is imported only once. If you need to See example usage in React Native template's [Podfile](https://github.com/facebook/react-native/blob/0.60-stable/template/ios/Podfile). -### Custom root (monorepos) - -The project root is where `node_modules` with `react-native` is. Autolinking script assume your project root to be `".."`, relative to `ios` directory. If you're in a project with custom structure, like this: - -``` -root/ - node_modules - example/ - ios/ -``` - -you'll need to set a custom root. Pass it as an argument to `use_native_modules!` function inside the targets and adjust the relatively required `native_modules` path accordingly: - -```rb -# example/ios/Podfile -require_relative '../../node_modules/@react-native-community/cli-platform-ios/native_modules' -target 'RNapp' do - # React pods and custom pods here... - use_native_modules!("../..") -end -``` - ## Platform Android The [native_modules.gradle](https://github.com/react-native-community/cli/blob/master/packages/platform-android/native_modules.gradle) script is included in your project's `settings.gradle` and `app/build.gradle` files and: From 391505dbde9cf3e7b41a36e9fb622be9af6102e2 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 20:59:55 +0200 Subject: [PATCH 04/43] wat --- packages/platform-ios/native_modules.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 358125c09..257a3c25c 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -152,7 +152,7 @@ def pluralize(count) } } @config = { - "project" => project, + "project" => @project, "dependencies" => { "ios-dep" => @ios_package, "android-dep" => @android_package @@ -224,10 +224,10 @@ def pluralize(count) end it "prints out the native module pods that were found" do - @podfile.use_native_modules({ "project" => project, "dependencies" => {} }) - @podfile.use_native_modules({ "project" => project, "dependencies" => { "pkg-1" => @ios_package }}) + @podfile.use_native_modules({ "project" => @project, "dependencies" => {} }) + @podfile.use_native_modules({ "project" => @project, "dependencies" => { "pkg-1" => @ios_package }}) @podfile.use_native_modules({ - "project" => project, "dependencies" => { "pkg-1" => @ios_package, "pkg-2" => @ios_package } + "project" => @project, "dependencies" => { "pkg-1" => @ios_package, "pkg-2" => @ios_package } }) @printed_messages.must_equal [ "Detected React Native module pod for ios-dep", From e0722c3202d32268badc4e4a825099c57c8a0888 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 21:03:02 +0200 Subject: [PATCH 05/43] Okay, this is how you do tests in Ruby --- packages/platform-ios/native_modules.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 257a3c25c..4f992930d 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -169,7 +169,7 @@ def pluralize(count) spec.singleton_class.send(:define_method, :name) { "ios-dep" } - podfile.singleton_class.send(:define_method, :use_native_modules) do |path, config| + podfile.singleton_class.send(:define_method, :use_native_modules) do |config| use_native_modules!(config) end From f85186fb9acb82a31c34bbb9cb54ca7423440e40 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 21:11:23 +0200 Subject: [PATCH 06/43] Fix Ruby tests --- packages/platform-ios/native_modules.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 4f992930d..48481e55f 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -59,7 +59,7 @@ def use_native_modules!(config = nil) relative_path = podspec_dir_path.relative_path_from project_root - pod spec.name, :path => relative_path + pod spec.name, :path => relative_path.to_path if package_config["scriptPhases"] # Can be either an object, or an array of objects @@ -148,7 +148,7 @@ def pluralize(count) } @project = { "ios" => { - "sourceDir": "/root/app" + "sourceDir" => "/root/app/ios" } } @config = { From 435d314e3b767db5dcad9aa9e281379f60d7d67e Mon Sep 17 00:00:00 2001 From: grabbou Date: Fri, 4 Oct 2019 14:55:06 +0200 Subject: [PATCH 07/43] Always resolve correct root --- packages/cli/package.json | 3 ++- packages/cli/src/tools/config/index.ts | 29 +++++++++++++++++++++++-- packages/platform-ios/native_modules.rb | 3 +-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 6e465cd75..571f29d57 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -40,6 +40,7 @@ "envinfo": "^7.1.0", "errorhandler": "^1.5.0", "execa": "^1.0.0", + "find-up": "^4.1.0", "fs-extra": "^7.0.1", "glob": "^7.1.1", "graceful-fs": "^4.1.3", @@ -69,8 +70,8 @@ }, "devDependencies": { "@types/command-exists": "^1.2.0", - "@types/graceful-fs": "^4.1.3", "@types/cosmiconfig": "^5.0.3", + "@types/graceful-fs": "^4.1.3", "@types/hapi__joi": "^15.0.4", "@types/minimist": "^1.2.0", "@types/mkdirp": "^0.5.2", diff --git a/packages/cli/src/tools/config/index.ts b/packages/cli/src/tools/config/index.ts index f5b1f1ca2..e0fd3d2d8 100644 --- a/packages/cli/src/tools/config/index.ts +++ b/packages/cli/src/tools/config/index.ts @@ -1,4 +1,5 @@ import path from 'path'; +import findUp from 'find-up'; import chalk from 'chalk'; import { UserDependencyConfig, @@ -7,7 +8,11 @@ import { UserConfig, Config, } from '@react-native-community/cli-types'; -import {logger, inlineString} from '@react-native-community/cli-tools'; +import { + logger, + inlineString, + CLIError, +} from '@react-native-community/cli-tools'; import * as ios from '@react-native-community/cli-platform-ios'; import * as android from '@react-native-community/cli-platform-android'; import findDependencies from './findDependencies'; @@ -58,10 +63,30 @@ function getDependencyConfig( ) as Dependency; } +/** + * Finds project root by looking for a closest `package.json`. + * + * Note: It is thetoretically possible that `package.json` doesn't exist + * in the tree. In that case, we choose to throw an error. + * + * When executing via `npx`, this will never happen as `npm` requires that file + * to be present in order to run + */ +const findProjectRoot = (): string => { + const packageLocation = findUp.sync('package.json'); + if (!packageLocation) { + throw new CLIError(` + We couldn't find a package.json in your project. + Are you sure you are running it inside a React Native project? + `); + } + return path.dirname(packageLocation); +}; + /** * Loads CLI configuration */ -function loadConfig(projectRoot: string = process.cwd()): Config { +function loadConfig(projectRoot: string = findProjectRoot()): Config { let lazyProject: ProjectConfig; const userConfig = readConfigFromDisk(projectRoot); diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 48481e55f..1a077f6d4 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -9,8 +9,7 @@ def use_native_modules!(config = nil) if (!config) json = [] - # @todo: Do not use Yarn here, but find path dynamically - IO.popen("yarn run --silent react-native config") do |data| + IO.popen("npx react-native config") do |data| while line = data.gets json << line end From 78065e02d275f7600647e892f586948cc04d1ee3 Mon Sep 17 00:00:00 2001 From: grabbou Date: Fri, 4 Oct 2019 15:01:35 +0200 Subject: [PATCH 08/43] Move files around --- .../cli/src/tools/config/findProjectRoot.ts | 26 +++++++++++++++++ packages/cli/src/tools/config/index.ts | 28 ++----------------- 2 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 packages/cli/src/tools/config/findProjectRoot.ts diff --git a/packages/cli/src/tools/config/findProjectRoot.ts b/packages/cli/src/tools/config/findProjectRoot.ts new file mode 100644 index 000000000..e90571879 --- /dev/null +++ b/packages/cli/src/tools/config/findProjectRoot.ts @@ -0,0 +1,26 @@ +import findUp from 'find-up'; +import path from 'path'; +import {CLIError} from '@react-native-community/cli-tools'; + +/** + * Finds project root by looking for a closest `package.json`. + */ +export default function findProjectRoot(): string { + const packageLocation = findUp.sync('package.json'); + + /** + * It is possible that `package.json` doesn't exist + * in the tree. In that case, we want to throw an error. + * + * When executing via `npx`, this will never happen as `npm` + * requires that file to be present in order to run. + */ + if (!packageLocation) { + throw new CLIError(` + We couldn't find a package.json in your project. + Are you sure you are running it inside a React Native project? + `); + } + + return path.dirname(packageLocation); +} diff --git a/packages/cli/src/tools/config/index.ts b/packages/cli/src/tools/config/index.ts index e0fd3d2d8..f0a5d1b2b 100644 --- a/packages/cli/src/tools/config/index.ts +++ b/packages/cli/src/tools/config/index.ts @@ -1,5 +1,4 @@ import path from 'path'; -import findUp from 'find-up'; import chalk from 'chalk'; import { UserDependencyConfig, @@ -8,14 +7,11 @@ import { UserConfig, Config, } from '@react-native-community/cli-types'; -import { - logger, - inlineString, - CLIError, -} from '@react-native-community/cli-tools'; +import {logger, inlineString} from '@react-native-community/cli-tools'; import * as ios from '@react-native-community/cli-platform-ios'; import * as android from '@react-native-community/cli-platform-android'; import findDependencies from './findDependencies'; +import findProjectRoot from './findProjectRoot'; import resolveReactNativePath from './resolveReactNativePath'; import findAssets from './findAssets'; import { @@ -63,26 +59,6 @@ function getDependencyConfig( ) as Dependency; } -/** - * Finds project root by looking for a closest `package.json`. - * - * Note: It is thetoretically possible that `package.json` doesn't exist - * in the tree. In that case, we choose to throw an error. - * - * When executing via `npx`, this will never happen as `npm` requires that file - * to be present in order to run - */ -const findProjectRoot = (): string => { - const packageLocation = findUp.sync('package.json'); - if (!packageLocation) { - throw new CLIError(` - We couldn't find a package.json in your project. - Are you sure you are running it inside a React Native project? - `); - } - return path.dirname(packageLocation); -}; - /** * Loads CLI configuration */ From 80be9d25457f45a96d30d2cf895745020817c780 Mon Sep 17 00:00:00 2001 From: grabbou Date: Fri, 4 Oct 2019 15:17:15 +0200 Subject: [PATCH 09/43] Add tests - one is failing, need to check why --- .../config/__tests__/findProjectRoot-test.ts | 43 +++++++++++++++++++ .../cli/src/tools/config/findProjectRoot.ts | 4 +- 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts diff --git a/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts new file mode 100644 index 000000000..df1329ff3 --- /dev/null +++ b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts @@ -0,0 +1,43 @@ +import path from 'path'; +import findProjectRoot from '../findProjectRoot'; +import { + cleanup, + writeFiles, + getTempDirectory, +} from '../../../../../../jest/helpers'; + +beforeEach(() => { + cleanup(DIR); + jest.resetModules(); +}); + +afterEach(() => cleanup(DIR)); + +const DIR = getTempDirectory('find_project_root_test'); + +test('resolves to correct project root', () => { + writeFiles(DIR, { + 'package.json': '{}', + ios: { + Podfile: '', + }, + }); + const cwd = path.join(DIR, 'ios'); + expect(findProjectRoot(cwd)).toBe(DIR); +}); + +test('resolves to correct project root in a monorepo', () => { + writeFiles(DIR, { + 'package.json': '{}', + packages: { + mobile: { + 'package.json': '{}', + ios: { + Podfile: '', + }, + }, + }, + }); + const cwd = path.join(DIR, 'packages/mobile/ios'); + expect(findProjectRoot(cwd)).toBe(path.join(DIR, 'packages/mobile')); +}); diff --git a/packages/cli/src/tools/config/findProjectRoot.ts b/packages/cli/src/tools/config/findProjectRoot.ts index e90571879..90bbf5bbd 100644 --- a/packages/cli/src/tools/config/findProjectRoot.ts +++ b/packages/cli/src/tools/config/findProjectRoot.ts @@ -5,8 +5,8 @@ import {CLIError} from '@react-native-community/cli-tools'; /** * Finds project root by looking for a closest `package.json`. */ -export default function findProjectRoot(): string { - const packageLocation = findUp.sync('package.json'); +export default function findProjectRoot(cwd = process.cwd()): string { + const packageLocation = findUp.sync('package.json', {cwd}); /** * It is possible that `package.json` doesn't exist From 3495fe5b00ceeba8befedff76f22357dd80505e7 Mon Sep 17 00:00:00 2001 From: grabbou Date: Fri, 4 Oct 2019 15:18:33 +0200 Subject: [PATCH 10/43] Fix tests --- .../tools/config/__tests__/findProjectRoot-test.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts index df1329ff3..27ea40431 100644 --- a/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts +++ b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts @@ -18,9 +18,7 @@ const DIR = getTempDirectory('find_project_root_test'); test('resolves to correct project root', () => { writeFiles(DIR, { 'package.json': '{}', - ios: { - Podfile: '', - }, + 'ios/Podfile': '', }); const cwd = path.join(DIR, 'ios'); expect(findProjectRoot(cwd)).toBe(DIR); @@ -29,14 +27,8 @@ test('resolves to correct project root', () => { test('resolves to correct project root in a monorepo', () => { writeFiles(DIR, { 'package.json': '{}', - packages: { - mobile: { - 'package.json': '{}', - ios: { - Podfile: '', - }, - }, - }, + 'packages/mobile/package.json': '{}', + 'packages/mobile/ios/Podfile': '', }); const cwd = path.join(DIR, 'packages/mobile/ios'); expect(findProjectRoot(cwd)).toBe(path.join(DIR, 'packages/mobile')); From 7e46d7758bdab0dc3e9a32c40e49571a3ecb77b4 Mon Sep 17 00:00:00 2001 From: grabbou Date: Fri, 4 Oct 2019 15:19:34 +0200 Subject: [PATCH 11/43] Assert it works from the same level --- packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts index 27ea40431..4504a2bfb 100644 --- a/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts +++ b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts @@ -22,6 +22,7 @@ test('resolves to correct project root', () => { }); const cwd = path.join(DIR, 'ios'); expect(findProjectRoot(cwd)).toBe(DIR); + expect(findProjectRoot(DIR)).toBe(DIR); }); test('resolves to correct project root in a monorepo', () => { From 68639b7d8102e309e41b36641115f464dca38601 Mon Sep 17 00:00:00 2001 From: grabbou Date: Mon, 7 Oct 2019 15:30:09 +0200 Subject: [PATCH 12/43] Warn if the root is passed We do not need root anymore. However, we still accept one argument (config) for testing purposes. Without this check, users that pass custom root would accidentially break their projects as CLI would take it as a config value. --- packages/platform-ios/native_modules.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 1a077f6d4..c44d53983 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -6,6 +6,14 @@ require 'pathname' def use_native_modules!(config = nil) + if (config.is_a? String) + Pod::UI.warn("Passing custom root to use_native_modules! is deprecated.", + [ + "CLI detects root of the project automatically. The \"#{config}\" argument was ignored.", + ]); + config = nil; + end + if (!config) json = [] From f8de995fa88846c67626a8755ee8895f34a5a1ed Mon Sep 17 00:00:00 2001 From: grabbou Date: Tue, 8 Oct 2019 21:24:43 +0200 Subject: [PATCH 13/43] Implement monorepo support for Android --- docs/autolinking.md | 25 -------- .../platform-android/native_modules.gradle | 62 +++++-------------- 2 files changed, 14 insertions(+), 73 deletions(-) diff --git a/docs/autolinking.md b/docs/autolinking.md index cfc03423b..8b53e1eb2 100644 --- a/docs/autolinking.md +++ b/docs/autolinking.md @@ -54,31 +54,6 @@ See example usage in React Native template: - [app/build.gradle](https://github.com/facebook/react-native/blob/0.60-stable/template/android/app/build.gradle#L185) - [MainApplication.java](https://github.com/facebook/react-native/blob/769e35ba5f4c31ef913035a5cc8bc0e88546ca55/template/android/app/src/main/java/com/helloworld/MainApplication.java#L22-L28) -### Custom root (monorepos) - -The project root is where `node_modules` with `react-native` is. Autolinking scripts assume your project root to be `".."`, relative to `android` directory. If you're in a project with custom structure, like this: - -``` -root/ - node_modules - example/ - android/ -``` - -you'll need to set a custom root. Pass it as a second argument to `applyNativeModulesSettingsGradle` and `applyNativeModulesAppBuildGradle` methods and adjust the `native_modules.gradle` path accordingly: - -```groovy -// example/android/settings.gradle -apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); -applyNativeModulesSettingsGradle(settings, "../..") -``` - -```groovy -// example/android/app/build.gradle -apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); -applyNativeModulesAppBuildGradle(project, "../..") -``` - ## What do I need to have in my package to make it work? You’re already using Gradle, so Android support will work by default. diff --git a/packages/platform-android/native_modules.gradle b/packages/platform-android/native_modules.gradle index f9bf5dd7a..3e89a2455 100644 --- a/packages/platform-android/native_modules.gradle +++ b/packages/platform-android/native_modules.gradle @@ -69,38 +69,23 @@ public class PackageList { class ReactNativeModules { private Logger logger - private Project project private String packageName - private DefaultSettings defaultSettings - private String root private ArrayList> reactNativeModules private static String LOG_PREFIX = ":ReactNative:" ReactNativeModules(Logger logger) { this.logger = logger - } - - void applySettingsGradle(DefaultSettings defaultSettings, String root) { - this.defaultSettings = defaultSettings - this.root = root - this.reactNativeModules = this.getReactNativeConfig() - - addReactNativeModuleProjects() - } - - void applyBuildGradle(Project project, String root) { - this.project = project - this.root = root - this.reactNativeModules = this.getReactNativeConfig() - - addReactNativeModuleDependencies() + + def (nativeModules, packageName) = this.getReactNativeConfig() + this.reactNativeModules = nativeModules + this.packageName = packageName } /** * Include the react native modules android projects and specify their project directory */ - void addReactNativeModuleProjects() { + void addReactNativeModuleProjects(DefaultSettings defaultSettings) { reactNativeModules.forEach { reactNativeModule -> String nameCleansed = reactNativeModule["nameCleansed"] String androidSourceDir = reactNativeModule["androidSourceDir"] @@ -112,33 +97,16 @@ class ReactNativeModules { /** * Adds the react native modules as dependencies to the users `app` project */ - void addReactNativeModuleDependencies() { + void addReactNativeModuleDependencies(Project appProject) { reactNativeModules.forEach { reactNativeModule -> def nameCleansed = reactNativeModule["nameCleansed"] - project.dependencies { + appProject.dependencies { // TODO(salakar): are other dependency scope methods such as `api` required? implementation project(path: ":${nameCleansed}") } } } - /** - * Returns the user's project root (i.e. where the node_modules dir is located). - */ - File getReactNativeProjectRoot() { - File androidRoot - - if (this.project) { - androidRoot = this.project.rootProject.projectDir - } else { - androidRoot = this.defaultSettings.rootProject.projectDir - } - - File rnRoot = new File(androidRoot, this.root) - this.logger.debug("${LOG_PREFIX}Using React Native project root path '${rnRoot.toString()}'") - return rnRoot - } - /** * Code-gen a java file with all the detected ReactNativePackage instances automatically added * @@ -182,12 +150,11 @@ class ReactNativeModules { ArrayList> reactNativeModules = new ArrayList>() def cmdProcess - def root = getReactNativeProjectRoot() - def command = "node ./node_modules/react-native/cli.js config" + def command = "npx react-native config" def reactNativeConfigOutput = "" try { - cmdProcess = Runtime.getRuntime().exec(command, null, root) + cmdProcess = Runtime.getRuntime().exec(command) def bufferedReader = new BufferedReader(new InputStreamReader(cmdProcess.getInputStream())) def buff = "" def readBuffer = new StringBuffer() @@ -211,7 +178,6 @@ class ReactNativeModules { } def json = new JsonSlurper().parseText(reactNativeConfigOutput) - this.packageName = json["project"]["android"]["packageName"] def dependencies = json["dependencies"] dependencies.each { name, value -> @@ -235,7 +201,7 @@ class ReactNativeModules { } } - return reactNativeModules + return [reactNativeModules, json["project"]["android"]["packageName"]]; } } @@ -245,12 +211,12 @@ class ReactNativeModules { def autoModules = new ReactNativeModules(logger) -ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings, String root = ".." -> - autoModules.applySettingsGradle(defaultSettings, root) +ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings -> + autoModules.addReactNativeModuleProjects(defaultSettings) } -ext.applyNativeModulesAppBuildGradle = { Project project, String root = ".." -> - autoModules.applyBuildGradle(project, root) +ext.applyNativeModulesAppBuildGradle = { Project project -> + autoModules.addReactNativeModuleDependencies(project) def generatedSrcDir = new File(buildDir, "generated/rncli/src/main/java") def generatedCodeDir = new File(generatedSrcDir, generatedFilePackage.replace('.', '/')) From 5041be86943ee939a18cf4263edfbcc993c0548c Mon Sep 17 00:00:00 2001 From: grabbou Date: Tue, 8 Oct 2019 21:37:39 +0200 Subject: [PATCH 14/43] Note custom paths --- docs/autolinking.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/autolinking.md b/docs/autolinking.md index 8b53e1eb2..eb8d009aa 100644 --- a/docs/autolinking.md +++ b/docs/autolinking.md @@ -95,3 +95,14 @@ module.exports = { }, }; ``` + +## How can I use autolinking in a monorepo? + +There is nothing extra you need to do - monorepos are supported by default. + +Please note that in certain scenarios, such as when using Yarn workspaces, your packages might be hoisted to the root of the repository. If that is the case, please make sure that the following paths are pointing to the +correct location and update them accordingly: + +- path to `native_modules.rb` in your `ios/Podfile` +- path to `native_modules.gradle` in your `android/settings.gradle` +- path to `native_modules.gradle` in your `android/app/build.gradle` From 53f59d175cf390b7e308930e261c6d32ab8c2b42 Mon Sep 17 00:00:00 2001 From: grabbou Date: Tue, 8 Oct 2019 21:50:34 +0200 Subject: [PATCH 15/43] Add quiet flag --- packages/platform-android/native_modules.gradle | 2 +- packages/platform-ios/native_modules.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/platform-android/native_modules.gradle b/packages/platform-android/native_modules.gradle index 3e89a2455..5264eeacd 100644 --- a/packages/platform-android/native_modules.gradle +++ b/packages/platform-android/native_modules.gradle @@ -150,7 +150,7 @@ class ReactNativeModules { ArrayList> reactNativeModules = new ArrayList>() def cmdProcess - def command = "npx react-native config" + def command = "npx --quiet react-native config" def reactNativeConfigOutput = "" try { diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index c44d53983..431282afb 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -13,11 +13,11 @@ def use_native_modules!(config = nil) ]); config = nil; end - + if (!config) json = [] - IO.popen("npx react-native config") do |data| + IO.popen("npx --quiet react-native config") do |data| while line = data.gets json << line end From 9dd0ce1284912d59fa4adf26437e90ba5b82c158 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 20:30:02 +0200 Subject: [PATCH 16/43] Improve handling of files in monorepo --- packages/platform-ios/native_modules.rb | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index d42cc26b1..a34a8d55e 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -5,24 +5,23 @@ # require 'pathname' -def use_native_modules!(root = "..", config = nil) +def use_native_modules!(config = nil) if (!config) json = [] - # Make sure `react-native config` is ran from your project root - Dir.chdir(root) do - IO.popen("./node_modules/.bin/react-native config") do |data| - while line = data.gets - json << line - end + # @todo: Do not use Yarn here, but find path dynamically + IO.popen("yarn run --silent react-native config") do |data| + while line = data.gets + json << line end end config = JSON.parse(json.join("\n")) end + project_root = Pathname.new(config["project"]["ios"]["sourceDir"]) + packages = config["dependencies"] - config_root = config["root"] found_pods = [] packages.each do |package_name, package| @@ -57,10 +56,10 @@ def use_native_modules!(root = "..", config = nil) end podspec_dir_path = Pathname.new(File.dirname(podspec_path)) - project_root = Pathname.new(config_root) + relative_path = podspec_dir_path.relative_path_from project_root - pod spec.name, :path => File.join(root, relative_path) + pod spec.name, :path => relative_path if package_config["scriptPhases"] # Can be either an object, or an array of objects From 3be7ea466e934e2ed27153486336a4cf8390f676 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 20:56:17 +0200 Subject: [PATCH 17/43] Fix tests with my poor Ruby haha --- packages/platform-ios/native_modules.rb | 28 ++++++++++++++----------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index a34a8d55e..358125c09 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -128,7 +128,6 @@ def pluralize(count) "execution_position" => "before_compile", "input" => "string" } - @ios_package = ios_package = { "root" => "/root/app/node_modules/react", "platforms" => { @@ -147,8 +146,13 @@ def pluralize(count) }, } } + @project = { + "ios" => { + "sourceDir": "/root/app" + } + } @config = { - "root" => "/root/app", + "project" => project, "dependencies" => { "ios-dep" => @ios_package, "android-dep" => @android_package @@ -166,7 +170,7 @@ def pluralize(count) spec.singleton_class.send(:define_method, :name) { "ios-dep" } podfile.singleton_class.send(:define_method, :use_native_modules) do |path, config| - use_native_modules!('..', config) + use_native_modules!(config) end Pod::Specification.singleton_class.send(:define_method, :from_file) do |podspec_path| @@ -196,7 +200,7 @@ def pluralize(count) end it "activates iOS pods" do - @podfile.use_native_modules('..', @config) + @podfile.use_native_modules(@config) @activated_pods.must_equal [{ name: "ios-dep", options: { path: "../node_modules/react" } @@ -207,7 +211,7 @@ def pluralize(count) activated_pod = Object.new activated_pod.singleton_class.send(:define_method, :name) { "ios-dep" } @current_target_definition_dependencies << activated_pod - @podfile.use_native_modules('..', @config) + @podfile.use_native_modules(@config) @activated_pods.must_equal [] end @@ -215,15 +219,15 @@ def pluralize(count) activated_pod = Object.new activated_pod.singleton_class.send(:define_method, :name) { "ios-dep/foo/bar" } @current_target_definition_dependencies << activated_pod - @podfile.use_native_modules('..', @config) + @podfile.use_native_modules(@config) @activated_pods.must_equal [] end it "prints out the native module pods that were found" do - @podfile.use_native_modules('..', { "root" => "/root/app", "dependencies" => {} }) - @podfile.use_native_modules('..', { "root" => "/root/app", "dependencies" => { "pkg-1" => @ios_package }}) - @podfile.use_native_modules('..', { - "root" => "/root/app", "dependencies" => { "pkg-1" => @ios_package, "pkg-2" => @ios_package } + @podfile.use_native_modules({ "project" => project, "dependencies" => {} }) + @podfile.use_native_modules({ "project" => project, "dependencies" => { "pkg-1" => @ios_package }}) + @podfile.use_native_modules({ + "project" => project, "dependencies" => { "pkg-1" => @ios_package, "pkg-2" => @ios_package } }) @printed_messages.must_equal [ "Detected React Native module pod for ios-dep", @@ -234,7 +238,7 @@ def pluralize(count) describe "concerning script_phases" do it "uses the options directly" do @config["dependencies"]["ios-dep"]["platforms"]["ios"]["scriptPhases"] = [@script_phase] - @podfile.use_native_modules('..', @config) + @podfile.use_native_modules(@config) @added_scripts.must_equal [{ :script => "123", :name => "My Name", @@ -252,7 +256,7 @@ def pluralize(count) file_read_mock.expect(:call, "contents from file", [File.join(@ios_package["root"], "some_shell_script.sh")]) File.stub(:read, file_read_mock) do - @podfile.use_native_modules('..', @config) + @podfile.use_native_modules(@config) end @added_scripts.must_equal [{ From 4091c4c93ecd9912f21e6bfbe10e12725bf37ea3 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 20:57:50 +0200 Subject: [PATCH 18/43] Remove note about monorepo from the docs --- docs/autolinking.md | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/docs/autolinking.md b/docs/autolinking.md index 99cf2b666..cfc03423b 100644 --- a/docs/autolinking.md +++ b/docs/autolinking.md @@ -36,28 +36,6 @@ The implementation ensures that a library is imported only once. If you need to See example usage in React Native template's [Podfile](https://github.com/facebook/react-native/blob/0.60-stable/template/ios/Podfile). -### Custom root (monorepos) - -The project root is where `node_modules` with `react-native` is. Autolinking script assume your project root to be `".."`, relative to `ios` directory. If you're in a project with custom structure, like this: - -``` -root/ - node_modules - example/ - ios/ -``` - -you'll need to set a custom root. Pass it as an argument to `use_native_modules!` function inside the targets and adjust the relatively required `native_modules` path accordingly: - -```rb -# example/ios/Podfile -require_relative '../../node_modules/@react-native-community/cli-platform-ios/native_modules' -target 'RNapp' do - # React pods and custom pods here... - use_native_modules!("../..") -end -``` - ## Platform Android The [native_modules.gradle](https://github.com/react-native-community/cli/blob/master/packages/platform-android/native_modules.gradle) script is included in your project's `settings.gradle` and `app/build.gradle` files and: From 27fac31efeb4cbe4c5676e8fffa43545ec500c45 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 20:59:55 +0200 Subject: [PATCH 19/43] wat --- packages/platform-ios/native_modules.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 358125c09..257a3c25c 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -152,7 +152,7 @@ def pluralize(count) } } @config = { - "project" => project, + "project" => @project, "dependencies" => { "ios-dep" => @ios_package, "android-dep" => @android_package @@ -224,10 +224,10 @@ def pluralize(count) end it "prints out the native module pods that were found" do - @podfile.use_native_modules({ "project" => project, "dependencies" => {} }) - @podfile.use_native_modules({ "project" => project, "dependencies" => { "pkg-1" => @ios_package }}) + @podfile.use_native_modules({ "project" => @project, "dependencies" => {} }) + @podfile.use_native_modules({ "project" => @project, "dependencies" => { "pkg-1" => @ios_package }}) @podfile.use_native_modules({ - "project" => project, "dependencies" => { "pkg-1" => @ios_package, "pkg-2" => @ios_package } + "project" => @project, "dependencies" => { "pkg-1" => @ios_package, "pkg-2" => @ios_package } }) @printed_messages.must_equal [ "Detected React Native module pod for ios-dep", From 0cbe32da85294aa8e3432162911e39ffeca9117a Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 21:03:02 +0200 Subject: [PATCH 20/43] Okay, this is how you do tests in Ruby --- packages/platform-ios/native_modules.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 257a3c25c..4f992930d 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -169,7 +169,7 @@ def pluralize(count) spec.singleton_class.send(:define_method, :name) { "ios-dep" } - podfile.singleton_class.send(:define_method, :use_native_modules) do |path, config| + podfile.singleton_class.send(:define_method, :use_native_modules) do |config| use_native_modules!(config) end From e362dc658f27620df2698fa147670f0685a63b84 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 3 Oct 2019 21:11:23 +0200 Subject: [PATCH 21/43] Fix Ruby tests --- packages/platform-ios/native_modules.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 4f992930d..48481e55f 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -59,7 +59,7 @@ def use_native_modules!(config = nil) relative_path = podspec_dir_path.relative_path_from project_root - pod spec.name, :path => relative_path + pod spec.name, :path => relative_path.to_path if package_config["scriptPhases"] # Can be either an object, or an array of objects @@ -148,7 +148,7 @@ def pluralize(count) } @project = { "ios" => { - "sourceDir": "/root/app" + "sourceDir" => "/root/app/ios" } } @config = { From 19fd10ea928a4033b83d90b3e2b05328e5ca62ff Mon Sep 17 00:00:00 2001 From: grabbou Date: Fri, 4 Oct 2019 14:55:06 +0200 Subject: [PATCH 22/43] Always resolve correct root --- packages/cli/package.json | 3 ++- packages/cli/src/tools/config/index.ts | 29 +++++++++++++++++++++++-- packages/platform-ios/native_modules.rb | 3 +-- 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 7f5e6497c..8d54bb3ab 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -42,6 +42,7 @@ "envinfo": "^7.1.0", "errorhandler": "^1.5.0", "execa": "^1.0.0", + "find-up": "^4.1.0", "fs-extra": "^7.0.1", "glob": "^7.1.1", "graceful-fs": "^4.1.3", @@ -71,8 +72,8 @@ }, "devDependencies": { "@types/command-exists": "^1.2.0", - "@types/graceful-fs": "^4.1.3", "@types/cosmiconfig": "^5.0.3", + "@types/graceful-fs": "^4.1.3", "@types/hapi__joi": "^15.0.4", "@types/minimist": "^1.2.0", "@types/mkdirp": "^0.5.2", diff --git a/packages/cli/src/tools/config/index.ts b/packages/cli/src/tools/config/index.ts index f5b1f1ca2..e0fd3d2d8 100644 --- a/packages/cli/src/tools/config/index.ts +++ b/packages/cli/src/tools/config/index.ts @@ -1,4 +1,5 @@ import path from 'path'; +import findUp from 'find-up'; import chalk from 'chalk'; import { UserDependencyConfig, @@ -7,7 +8,11 @@ import { UserConfig, Config, } from '@react-native-community/cli-types'; -import {logger, inlineString} from '@react-native-community/cli-tools'; +import { + logger, + inlineString, + CLIError, +} from '@react-native-community/cli-tools'; import * as ios from '@react-native-community/cli-platform-ios'; import * as android from '@react-native-community/cli-platform-android'; import findDependencies from './findDependencies'; @@ -58,10 +63,30 @@ function getDependencyConfig( ) as Dependency; } +/** + * Finds project root by looking for a closest `package.json`. + * + * Note: It is thetoretically possible that `package.json` doesn't exist + * in the tree. In that case, we choose to throw an error. + * + * When executing via `npx`, this will never happen as `npm` requires that file + * to be present in order to run + */ +const findProjectRoot = (): string => { + const packageLocation = findUp.sync('package.json'); + if (!packageLocation) { + throw new CLIError(` + We couldn't find a package.json in your project. + Are you sure you are running it inside a React Native project? + `); + } + return path.dirname(packageLocation); +}; + /** * Loads CLI configuration */ -function loadConfig(projectRoot: string = process.cwd()): Config { +function loadConfig(projectRoot: string = findProjectRoot()): Config { let lazyProject: ProjectConfig; const userConfig = readConfigFromDisk(projectRoot); diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 48481e55f..1a077f6d4 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -9,8 +9,7 @@ def use_native_modules!(config = nil) if (!config) json = [] - # @todo: Do not use Yarn here, but find path dynamically - IO.popen("yarn run --silent react-native config") do |data| + IO.popen("npx react-native config") do |data| while line = data.gets json << line end From 366b7c4228aca0777ca5854cefcffa2ffd43fa3d Mon Sep 17 00:00:00 2001 From: grabbou Date: Fri, 4 Oct 2019 15:01:35 +0200 Subject: [PATCH 23/43] Move files around --- .../cli/src/tools/config/findProjectRoot.ts | 26 +++++++++++++++++ packages/cli/src/tools/config/index.ts | 28 ++----------------- 2 files changed, 28 insertions(+), 26 deletions(-) create mode 100644 packages/cli/src/tools/config/findProjectRoot.ts diff --git a/packages/cli/src/tools/config/findProjectRoot.ts b/packages/cli/src/tools/config/findProjectRoot.ts new file mode 100644 index 000000000..e90571879 --- /dev/null +++ b/packages/cli/src/tools/config/findProjectRoot.ts @@ -0,0 +1,26 @@ +import findUp from 'find-up'; +import path from 'path'; +import {CLIError} from '@react-native-community/cli-tools'; + +/** + * Finds project root by looking for a closest `package.json`. + */ +export default function findProjectRoot(): string { + const packageLocation = findUp.sync('package.json'); + + /** + * It is possible that `package.json` doesn't exist + * in the tree. In that case, we want to throw an error. + * + * When executing via `npx`, this will never happen as `npm` + * requires that file to be present in order to run. + */ + if (!packageLocation) { + throw new CLIError(` + We couldn't find a package.json in your project. + Are you sure you are running it inside a React Native project? + `); + } + + return path.dirname(packageLocation); +} diff --git a/packages/cli/src/tools/config/index.ts b/packages/cli/src/tools/config/index.ts index e0fd3d2d8..f0a5d1b2b 100644 --- a/packages/cli/src/tools/config/index.ts +++ b/packages/cli/src/tools/config/index.ts @@ -1,5 +1,4 @@ import path from 'path'; -import findUp from 'find-up'; import chalk from 'chalk'; import { UserDependencyConfig, @@ -8,14 +7,11 @@ import { UserConfig, Config, } from '@react-native-community/cli-types'; -import { - logger, - inlineString, - CLIError, -} from '@react-native-community/cli-tools'; +import {logger, inlineString} from '@react-native-community/cli-tools'; import * as ios from '@react-native-community/cli-platform-ios'; import * as android from '@react-native-community/cli-platform-android'; import findDependencies from './findDependencies'; +import findProjectRoot from './findProjectRoot'; import resolveReactNativePath from './resolveReactNativePath'; import findAssets from './findAssets'; import { @@ -63,26 +59,6 @@ function getDependencyConfig( ) as Dependency; } -/** - * Finds project root by looking for a closest `package.json`. - * - * Note: It is thetoretically possible that `package.json` doesn't exist - * in the tree. In that case, we choose to throw an error. - * - * When executing via `npx`, this will never happen as `npm` requires that file - * to be present in order to run - */ -const findProjectRoot = (): string => { - const packageLocation = findUp.sync('package.json'); - if (!packageLocation) { - throw new CLIError(` - We couldn't find a package.json in your project. - Are you sure you are running it inside a React Native project? - `); - } - return path.dirname(packageLocation); -}; - /** * Loads CLI configuration */ From 553df50fd4bfea144cfbfa568fd9af644d9002cd Mon Sep 17 00:00:00 2001 From: grabbou Date: Fri, 4 Oct 2019 15:17:15 +0200 Subject: [PATCH 24/43] Add tests - one is failing, need to check why --- .../config/__tests__/findProjectRoot-test.ts | 43 +++++++++++++++++++ .../cli/src/tools/config/findProjectRoot.ts | 4 +- 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts diff --git a/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts new file mode 100644 index 000000000..df1329ff3 --- /dev/null +++ b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts @@ -0,0 +1,43 @@ +import path from 'path'; +import findProjectRoot from '../findProjectRoot'; +import { + cleanup, + writeFiles, + getTempDirectory, +} from '../../../../../../jest/helpers'; + +beforeEach(() => { + cleanup(DIR); + jest.resetModules(); +}); + +afterEach(() => cleanup(DIR)); + +const DIR = getTempDirectory('find_project_root_test'); + +test('resolves to correct project root', () => { + writeFiles(DIR, { + 'package.json': '{}', + ios: { + Podfile: '', + }, + }); + const cwd = path.join(DIR, 'ios'); + expect(findProjectRoot(cwd)).toBe(DIR); +}); + +test('resolves to correct project root in a monorepo', () => { + writeFiles(DIR, { + 'package.json': '{}', + packages: { + mobile: { + 'package.json': '{}', + ios: { + Podfile: '', + }, + }, + }, + }); + const cwd = path.join(DIR, 'packages/mobile/ios'); + expect(findProjectRoot(cwd)).toBe(path.join(DIR, 'packages/mobile')); +}); diff --git a/packages/cli/src/tools/config/findProjectRoot.ts b/packages/cli/src/tools/config/findProjectRoot.ts index e90571879..90bbf5bbd 100644 --- a/packages/cli/src/tools/config/findProjectRoot.ts +++ b/packages/cli/src/tools/config/findProjectRoot.ts @@ -5,8 +5,8 @@ import {CLIError} from '@react-native-community/cli-tools'; /** * Finds project root by looking for a closest `package.json`. */ -export default function findProjectRoot(): string { - const packageLocation = findUp.sync('package.json'); +export default function findProjectRoot(cwd = process.cwd()): string { + const packageLocation = findUp.sync('package.json', {cwd}); /** * It is possible that `package.json` doesn't exist From 858ac79621606f2e8aeb15e5f76a8337bac6fde7 Mon Sep 17 00:00:00 2001 From: grabbou Date: Fri, 4 Oct 2019 15:18:33 +0200 Subject: [PATCH 25/43] Fix tests --- .../tools/config/__tests__/findProjectRoot-test.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts index df1329ff3..27ea40431 100644 --- a/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts +++ b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts @@ -18,9 +18,7 @@ const DIR = getTempDirectory('find_project_root_test'); test('resolves to correct project root', () => { writeFiles(DIR, { 'package.json': '{}', - ios: { - Podfile: '', - }, + 'ios/Podfile': '', }); const cwd = path.join(DIR, 'ios'); expect(findProjectRoot(cwd)).toBe(DIR); @@ -29,14 +27,8 @@ test('resolves to correct project root', () => { test('resolves to correct project root in a monorepo', () => { writeFiles(DIR, { 'package.json': '{}', - packages: { - mobile: { - 'package.json': '{}', - ios: { - Podfile: '', - }, - }, - }, + 'packages/mobile/package.json': '{}', + 'packages/mobile/ios/Podfile': '', }); const cwd = path.join(DIR, 'packages/mobile/ios'); expect(findProjectRoot(cwd)).toBe(path.join(DIR, 'packages/mobile')); From 883068f741e5f7c0e88999a3ff317ae746c2a27c Mon Sep 17 00:00:00 2001 From: grabbou Date: Fri, 4 Oct 2019 15:19:34 +0200 Subject: [PATCH 26/43] Assert it works from the same level --- packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts index 27ea40431..4504a2bfb 100644 --- a/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts +++ b/packages/cli/src/tools/config/__tests__/findProjectRoot-test.ts @@ -22,6 +22,7 @@ test('resolves to correct project root', () => { }); const cwd = path.join(DIR, 'ios'); expect(findProjectRoot(cwd)).toBe(DIR); + expect(findProjectRoot(DIR)).toBe(DIR); }); test('resolves to correct project root in a monorepo', () => { From 7733cb274be54090fb7af3ae2cdbb62fbab80fdd Mon Sep 17 00:00:00 2001 From: grabbou Date: Mon, 7 Oct 2019 15:30:09 +0200 Subject: [PATCH 27/43] Warn if the root is passed We do not need root anymore. However, we still accept one argument (config) for testing purposes. Without this check, users that pass custom root would accidentially break their projects as CLI would take it as a config value. --- packages/platform-ios/native_modules.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index 1a077f6d4..c44d53983 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -6,6 +6,14 @@ require 'pathname' def use_native_modules!(config = nil) + if (config.is_a? String) + Pod::UI.warn("Passing custom root to use_native_modules! is deprecated.", + [ + "CLI detects root of the project automatically. The \"#{config}\" argument was ignored.", + ]); + config = nil; + end + if (!config) json = [] From c4c1745340883af344400b26e137f231fa04cfd4 Mon Sep 17 00:00:00 2001 From: grabbou Date: Tue, 8 Oct 2019 21:24:43 +0200 Subject: [PATCH 28/43] Implement monorepo support for Android --- docs/autolinking.md | 25 -------- .../platform-android/native_modules.gradle | 62 +++++-------------- 2 files changed, 14 insertions(+), 73 deletions(-) diff --git a/docs/autolinking.md b/docs/autolinking.md index cfc03423b..8b53e1eb2 100644 --- a/docs/autolinking.md +++ b/docs/autolinking.md @@ -54,31 +54,6 @@ See example usage in React Native template: - [app/build.gradle](https://github.com/facebook/react-native/blob/0.60-stable/template/android/app/build.gradle#L185) - [MainApplication.java](https://github.com/facebook/react-native/blob/769e35ba5f4c31ef913035a5cc8bc0e88546ca55/template/android/app/src/main/java/com/helloworld/MainApplication.java#L22-L28) -### Custom root (monorepos) - -The project root is where `node_modules` with `react-native` is. Autolinking scripts assume your project root to be `".."`, relative to `android` directory. If you're in a project with custom structure, like this: - -``` -root/ - node_modules - example/ - android/ -``` - -you'll need to set a custom root. Pass it as a second argument to `applyNativeModulesSettingsGradle` and `applyNativeModulesAppBuildGradle` methods and adjust the `native_modules.gradle` path accordingly: - -```groovy -// example/android/settings.gradle -apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); -applyNativeModulesSettingsGradle(settings, "../..") -``` - -```groovy -// example/android/app/build.gradle -apply from: file("../../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); -applyNativeModulesAppBuildGradle(project, "../..") -``` - ## What do I need to have in my package to make it work? You’re already using Gradle, so Android support will work by default. diff --git a/packages/platform-android/native_modules.gradle b/packages/platform-android/native_modules.gradle index f9bf5dd7a..3e89a2455 100644 --- a/packages/platform-android/native_modules.gradle +++ b/packages/platform-android/native_modules.gradle @@ -69,38 +69,23 @@ public class PackageList { class ReactNativeModules { private Logger logger - private Project project private String packageName - private DefaultSettings defaultSettings - private String root private ArrayList> reactNativeModules private static String LOG_PREFIX = ":ReactNative:" ReactNativeModules(Logger logger) { this.logger = logger - } - - void applySettingsGradle(DefaultSettings defaultSettings, String root) { - this.defaultSettings = defaultSettings - this.root = root - this.reactNativeModules = this.getReactNativeConfig() - - addReactNativeModuleProjects() - } - - void applyBuildGradle(Project project, String root) { - this.project = project - this.root = root - this.reactNativeModules = this.getReactNativeConfig() - - addReactNativeModuleDependencies() + + def (nativeModules, packageName) = this.getReactNativeConfig() + this.reactNativeModules = nativeModules + this.packageName = packageName } /** * Include the react native modules android projects and specify their project directory */ - void addReactNativeModuleProjects() { + void addReactNativeModuleProjects(DefaultSettings defaultSettings) { reactNativeModules.forEach { reactNativeModule -> String nameCleansed = reactNativeModule["nameCleansed"] String androidSourceDir = reactNativeModule["androidSourceDir"] @@ -112,33 +97,16 @@ class ReactNativeModules { /** * Adds the react native modules as dependencies to the users `app` project */ - void addReactNativeModuleDependencies() { + void addReactNativeModuleDependencies(Project appProject) { reactNativeModules.forEach { reactNativeModule -> def nameCleansed = reactNativeModule["nameCleansed"] - project.dependencies { + appProject.dependencies { // TODO(salakar): are other dependency scope methods such as `api` required? implementation project(path: ":${nameCleansed}") } } } - /** - * Returns the user's project root (i.e. where the node_modules dir is located). - */ - File getReactNativeProjectRoot() { - File androidRoot - - if (this.project) { - androidRoot = this.project.rootProject.projectDir - } else { - androidRoot = this.defaultSettings.rootProject.projectDir - } - - File rnRoot = new File(androidRoot, this.root) - this.logger.debug("${LOG_PREFIX}Using React Native project root path '${rnRoot.toString()}'") - return rnRoot - } - /** * Code-gen a java file with all the detected ReactNativePackage instances automatically added * @@ -182,12 +150,11 @@ class ReactNativeModules { ArrayList> reactNativeModules = new ArrayList>() def cmdProcess - def root = getReactNativeProjectRoot() - def command = "node ./node_modules/react-native/cli.js config" + def command = "npx react-native config" def reactNativeConfigOutput = "" try { - cmdProcess = Runtime.getRuntime().exec(command, null, root) + cmdProcess = Runtime.getRuntime().exec(command) def bufferedReader = new BufferedReader(new InputStreamReader(cmdProcess.getInputStream())) def buff = "" def readBuffer = new StringBuffer() @@ -211,7 +178,6 @@ class ReactNativeModules { } def json = new JsonSlurper().parseText(reactNativeConfigOutput) - this.packageName = json["project"]["android"]["packageName"] def dependencies = json["dependencies"] dependencies.each { name, value -> @@ -235,7 +201,7 @@ class ReactNativeModules { } } - return reactNativeModules + return [reactNativeModules, json["project"]["android"]["packageName"]]; } } @@ -245,12 +211,12 @@ class ReactNativeModules { def autoModules = new ReactNativeModules(logger) -ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings, String root = ".." -> - autoModules.applySettingsGradle(defaultSettings, root) +ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings -> + autoModules.addReactNativeModuleProjects(defaultSettings) } -ext.applyNativeModulesAppBuildGradle = { Project project, String root = ".." -> - autoModules.applyBuildGradle(project, root) +ext.applyNativeModulesAppBuildGradle = { Project project -> + autoModules.addReactNativeModuleDependencies(project) def generatedSrcDir = new File(buildDir, "generated/rncli/src/main/java") def generatedCodeDir = new File(generatedSrcDir, generatedFilePackage.replace('.', '/')) From a13e47fdaf83bdcb80399d5e30e0f137715edcc8 Mon Sep 17 00:00:00 2001 From: grabbou Date: Tue, 8 Oct 2019 21:37:39 +0200 Subject: [PATCH 29/43] Note custom paths --- docs/autolinking.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/autolinking.md b/docs/autolinking.md index 8b53e1eb2..eb8d009aa 100644 --- a/docs/autolinking.md +++ b/docs/autolinking.md @@ -95,3 +95,14 @@ module.exports = { }, }; ``` + +## How can I use autolinking in a monorepo? + +There is nothing extra you need to do - monorepos are supported by default. + +Please note that in certain scenarios, such as when using Yarn workspaces, your packages might be hoisted to the root of the repository. If that is the case, please make sure that the following paths are pointing to the +correct location and update them accordingly: + +- path to `native_modules.rb` in your `ios/Podfile` +- path to `native_modules.gradle` in your `android/settings.gradle` +- path to `native_modules.gradle` in your `android/app/build.gradle` From bdcc9faa30c647b6b9db0c7e7edbce2a07630c17 Mon Sep 17 00:00:00 2001 From: grabbou Date: Tue, 8 Oct 2019 21:50:34 +0200 Subject: [PATCH 30/43] Add quiet flag --- packages/platform-android/native_modules.gradle | 2 +- packages/platform-ios/native_modules.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/platform-android/native_modules.gradle b/packages/platform-android/native_modules.gradle index 3e89a2455..5264eeacd 100644 --- a/packages/platform-android/native_modules.gradle +++ b/packages/platform-android/native_modules.gradle @@ -150,7 +150,7 @@ class ReactNativeModules { ArrayList> reactNativeModules = new ArrayList>() def cmdProcess - def command = "npx react-native config" + def command = "npx --quiet react-native config" def reactNativeConfigOutput = "" try { diff --git a/packages/platform-ios/native_modules.rb b/packages/platform-ios/native_modules.rb index c44d53983..431282afb 100644 --- a/packages/platform-ios/native_modules.rb +++ b/packages/platform-ios/native_modules.rb @@ -13,11 +13,11 @@ def use_native_modules!(config = nil) ]); config = nil; end - + if (!config) json = [] - IO.popen("npx react-native config") do |data| + IO.popen("npx --quiet react-native config") do |data| while line = data.gets json << line end From 07bd62e0c5271f250dd72e02cd5ba7a93ff32f10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Pierzcha=C5=82a?= Date: Thu, 10 Oct 2019 12:05:10 +0200 Subject: [PATCH 31/43] update locfile --- .../cli/src/tools/config/findProjectRoot.ts | 2 +- yarn.lock | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/packages/cli/src/tools/config/findProjectRoot.ts b/packages/cli/src/tools/config/findProjectRoot.ts index 90bbf5bbd..32b3c2e28 100644 --- a/packages/cli/src/tools/config/findProjectRoot.ts +++ b/packages/cli/src/tools/config/findProjectRoot.ts @@ -17,7 +17,7 @@ export default function findProjectRoot(cwd = process.cwd()): string { */ if (!packageLocation) { throw new CLIError(` - We couldn't find a package.json in your project. + We couldn't find a package.json in your project. Are you sure you are running it inside a React Native project? `); } diff --git a/yarn.lock b/yarn.lock index 08af35747..dd6834730 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4367,6 +4367,14 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + flat-cache@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" @@ -6123,6 +6131,13 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -7317,6 +7332,13 @@ p-limit@^2.0.0: dependencies: p-try "^2.0.0" +p-limit@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + dependencies: + p-try "^2.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -7330,6 +7352,13 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-map-series@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca" @@ -7491,6 +7520,11 @@ path-exists@^3.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" From 858ea5eef7be824592db6168d2de8d8b76dfa758 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 13:18:03 +0200 Subject: [PATCH 32/43] Fix init - make detachedCommands and remove ugly setProjectDir hack --- packages/cli-types/src/index.ts | 10 +++++++++ packages/cli/src/cliEntry.js | 22 ++++++++++++------- packages/cli/src/commands/index.ts | 7 +++--- packages/cli/src/commands/init/index.ts | 1 + packages/cli/src/commands/init/init.ts | 9 ++++---- packages/cli/src/commands/install/install.ts | 5 +++-- .../cli/src/commands/install/uninstall.ts | 2 +- packages/cli/src/commands/upgrade/upgrade.ts | 9 ++++---- packages/cli/src/tools/packageManager.ts | 21 +++++++----------- packages/cli/src/tools/yarn.ts | 13 ++++------- types/index.js | 1 + 11 files changed, 56 insertions(+), 44 deletions(-) diff --git a/packages/cli-types/src/index.ts b/packages/cli-types/src/index.ts index 7738f22ec..df93441e0 100644 --- a/packages/cli-types/src/index.ts +++ b/packages/cli-types/src/index.ts @@ -39,6 +39,16 @@ export interface Command { }>; } +export type DetachedCommandFunction = ( + argv: Array, + args: Args, +) => Promise | void; + +export type DetachedCommand = Command & { + detached: true; + func: DetachedCommandFunction; +}; + interface PlatformConfig< ProjectConfig, ProjectParams, diff --git a/packages/cli/src/cliEntry.js b/packages/cli/src/cliEntry.js index f65fc8558..25a9c403e 100644 --- a/packages/cli/src/cliEntry.js +++ b/packages/cli/src/cliEntry.js @@ -14,14 +14,12 @@ import path from 'path'; import type {CommandT, ConfigT} from 'types'; // $FlowFixMe - converted to TS -import commands from './commands'; +import {detachedCommands, projectCommands} from './commands'; // $FlowFixMe - converted to TS import init from './commands/init/initCompat'; // $FlowFixMe - converted to TS import assertRequiredOptions from './tools/assertRequiredOptions'; import {logger} from '@react-native-community/cli-tools'; -// $FlowFixMe - converted to TS -import {setProjectDir} from './tools/packageManager'; import pkgJson from '../package.json'; // $FlowFixMe - converted to TS import loadConfig from './tools/config'; @@ -117,7 +115,11 @@ const addCommand = (command: CommandT, ctx: ConfigT) => { try { assertRequiredOptions(options, passedOptions); - await command.func(argv, ctx, passedOptions); + if (command.detached) { + await command.func(argv, passedOptions); + } else { + await command.func(argv, ctx, passedOptions); + } } catch (error) { handleError(error); } @@ -174,13 +176,17 @@ async function setupAndRun() { logger.disable(); } - const ctx = loadConfig(); - logger.enable(); - setProjectDir(ctx.root); + detachedCommands.forEach(addCommand); - [...commands, ...ctx.commands].forEach(command => addCommand(command, ctx)); + try { + const ctx = loadConfig(); + + [...projectCommands, ...ctx.commands].forEach(command => + addCommand(command, ctx), + ); + } catch (e) {} commander.parse(process.argv); diff --git a/packages/cli/src/commands/index.ts b/packages/cli/src/commands/index.ts index 64dce9ebc..bf0423856 100644 --- a/packages/cli/src/commands/index.ts +++ b/packages/cli/src/commands/index.ts @@ -1,4 +1,4 @@ -import {Command} from '@react-native-community/cli-types'; +import {DetachedCommand, Command} from '@react-native-community/cli-types'; // @ts-ignore - JS file import server from './server/server'; @@ -15,7 +15,7 @@ import init from './init'; // @ts-ignore - JS file import doctor from './doctor'; -export default [ +export const projectCommands = [ server, bundle, ramBundle, @@ -26,6 +26,7 @@ export default [ upgrade, info, config, - init, doctor, ] as Command[]; + +export const detachedCommands = [init] as DetachedCommand[]; diff --git a/packages/cli/src/commands/init/index.ts b/packages/cli/src/commands/init/index.ts index 4b76ba7f3..244446385 100644 --- a/packages/cli/src/commands/init/index.ts +++ b/packages/cli/src/commands/init/index.ts @@ -2,6 +2,7 @@ import init from './init'; export default { func: init, + detached: true, name: 'init ', description: 'Initialize a new React Native project named in a directory of the same name.', diff --git a/packages/cli/src/commands/init/init.ts b/packages/cli/src/commands/init/init.ts index 14459a898..34620aa71 100644 --- a/packages/cli/src/commands/init/init.ts +++ b/packages/cli/src/commands/init/init.ts @@ -11,7 +11,6 @@ import {validateProjectName} from './validate'; import DirectoryAlreadyExistsError from './errors/DirectoryAlreadyExistsError'; import printRunInstructions from './printRunInstructions'; import {CLIError, logger} from '@react-native-community/cli-tools'; -import {Config} from '@react-native-community/cli-types'; import { installTemplatePackage, getTemplateConfig, @@ -152,7 +151,7 @@ async function createFromTemplate({ loader.succeed(); } - await installDependencies({projectName, npm, loader}); + await installDependencies({projectName, npm, loader, directory}); } catch (e) { loader.fail(); throw new Error(e); @@ -165,16 +164,19 @@ async function installDependencies({ projectName, npm, loader, + directory, }: { projectName: string; npm?: boolean; loader: ora.Ora; + directory: string; }) { loader.start('Installing dependencies'); await PackageManager.installAll({ preferYarn: !npm, silent: true, + root: directory, }); if (process.platform === 'darwin') { @@ -213,10 +215,9 @@ async function createProject( export default (async function initialize( [projectName]: Array, - context: Config, options: Options, ) { - const rootFolder = context.root; + const rootFolder = process.cwd(); validateProjectName(projectName); diff --git a/packages/cli/src/commands/install/install.ts b/packages/cli/src/commands/install/install.ts index 6f3a8fbce..a630247f7 100644 --- a/packages/cli/src/commands/install/install.ts +++ b/packages/cli/src/commands/install/install.ts @@ -9,12 +9,13 @@ import {logger} from '@react-native-community/cli-tools'; import * as PackageManager from '../../tools/packageManager'; import link from '../link/link'; import loadConfig from '../../tools/config'; +import {Config} from '@react-native-community/cli-types'; -async function install(args: Array): Promise { +async function install(args: Array, ctx: Config): Promise { const name = args[0]; logger.info(`Installing "${name}"...`); - await PackageManager.install([name]); + await PackageManager.install([name], {root: ctx.root}); // Reload configuration to see newly installed dependency const newConfig = loadConfig(); diff --git a/packages/cli/src/commands/install/uninstall.ts b/packages/cli/src/commands/install/uninstall.ts index a82e6c71a..f5c46bf1b 100644 --- a/packages/cli/src/commands/install/uninstall.ts +++ b/packages/cli/src/commands/install/uninstall.ts @@ -17,7 +17,7 @@ async function uninstall(args: Array, ctx: Config): Promise { await unlink.func([name], ctx, {}); logger.info(`Uninstalling "${name}"...`); - await PackageManager.uninstall([name]); + await PackageManager.uninstall([name], {root: ctx.root}); logger.success(`Successfully uninstalled and unlinked "${name}"`); } diff --git a/packages/cli/src/commands/upgrade/upgrade.ts b/packages/cli/src/commands/upgrade/upgrade.ts index 1b419e0cb..162644bba 100644 --- a/packages/cli/src/commands/upgrade/upgrade.ts +++ b/packages/cli/src/commands/upgrade/upgrade.ts @@ -138,7 +138,7 @@ const getVersionToUpgradeTo = async ( return newVersion; }; -const installDeps = async (newVersion: string) => { +const installDeps = async (root: string, newVersion: string) => { logger.info( `Installing "react-native@${newVersion}" and its peer dependencies...`, ); @@ -149,6 +149,7 @@ const installDeps = async (newVersion: string) => { ]; await PackageManager.install(deps, { silent: true, + root, }); await execa('git', ['add', 'package.json']); try { @@ -314,7 +315,7 @@ async function upgrade(argv: Array, ctx: Config) { if (patch === '') { logger.info('Diff has no changes to apply, proceeding further'); - await installDeps(newVersion); + await installDeps(projectDir, newVersion); await installCocoaPodsDeps(projectDir, thirdPartyIOSDeps); logger.success( @@ -341,7 +342,7 @@ async function upgrade(argv: Array, ctx: Config) { logger.warn( 'Continuing after failure. Some of the files are upgraded but you will need to deal with conflicts manually', ); - await installDeps(newVersion); + await installDeps(projectDir, newVersion); logger.info('Running "git status" to check what changed...'); await execa('git', ['status'], {stdio: 'inherit'}); } else { @@ -350,7 +351,7 @@ async function upgrade(argv: Array, ctx: Config) { ); } } else { - await installDeps(newVersion); + await installDeps(projectDir, newVersion); await installCocoaPodsDeps(projectDir, thirdPartyIOSDeps); logger.info('Running "git status" to check what changed...'); await execa('git', ['status'], {stdio: 'inherit'}); diff --git a/packages/cli/src/tools/packageManager.ts b/packages/cli/src/tools/packageManager.ts index 15282cef3..e9f0bd783 100644 --- a/packages/cli/src/tools/packageManager.ts +++ b/packages/cli/src/tools/packageManager.ts @@ -6,10 +6,9 @@ type Options = { preferYarn?: boolean; silent?: boolean; cwd?: string; + root: string; }; -let projectDir: string; - const packageManagers = { yarn: { install: ['add'], @@ -28,7 +27,7 @@ const packageManagers = { function configurePackageManager( packageNames: Array, action: 'install' | 'installDev' | 'installAll' | 'uninstall', - options?: Options, + options: Options, ) { const pm = shouldUseYarn(options) ? 'yarn' : 'npm'; const [executable, ...flags] = packageManagers[pm][action]; @@ -48,30 +47,26 @@ function executeCommand( }); } -function shouldUseYarn(options?: Options) { +function shouldUseYarn(options: Options) { if (options && options.preferYarn !== undefined) { return options.preferYarn && getYarnVersionIfAvailable(); } - return isProjectUsingYarn(projectDir) && getYarnVersionIfAvailable(); -} - -export function setProjectDir(dir: string) { - projectDir = dir; + return isProjectUsingYarn(options.root) && getYarnVersionIfAvailable(); } -export function install(packageNames: Array, options?: Options) { +export function install(packageNames: Array, options: Options) { return configurePackageManager(packageNames, 'install', options); } -export function installDev(packageNames: Array, options?: Options) { +export function installDev(packageNames: Array, options: Options) { return configurePackageManager(packageNames, 'installDev', options); } -export function uninstall(packageNames: Array, options?: Options) { +export function uninstall(packageNames: Array, options: Options) { return configurePackageManager(packageNames, 'uninstall', options); } -export function installAll(options?: Options) { +export function installAll(options: Options) { return configurePackageManager([], 'installAll', options); } diff --git a/packages/cli/src/tools/yarn.ts b/packages/cli/src/tools/yarn.ts index cb971e61c..45a8f463a 100644 --- a/packages/cli/src/tools/yarn.ts +++ b/packages/cli/src/tools/yarn.ts @@ -7,10 +7,9 @@ */ import {execSync} from 'child_process'; -import fs from 'fs'; -import path from 'path'; import semver from 'semver'; import {logger} from '@react-native-community/cli-tools'; +import findUp from 'find-up'; /** * Use Yarn if available, it's much faster than the npm client. @@ -41,12 +40,8 @@ export function getYarnVersionIfAvailable() { } /** - * Check that 'react-native init' itself used yarn to install React Native. - * When using an old global react-native-cli@1.0.0 (or older), we don't want - * to install React Native with npm, and React + Jest with yarn. - * Let's be safe and not mix yarn and npm in a single project. - * @param projectDir e.g. /Users/martin/AwesomeApp + * Check if project is using Yarn (has `yarn.lock` in the tree) */ -export function isProjectUsingYarn(projectDir: string) { - return fs.existsSync(path.join(projectDir, 'yarn.lock')); +export function isProjectUsingYarn(cwd: string) { + return findUp.sync('yarn.lock', {cwd}); } diff --git a/types/index.js b/types/index.js index 1c09e0a3e..025d2ef11 100644 --- a/types/index.js +++ b/types/index.js @@ -4,6 +4,7 @@ export type CommandT = { name: string, description?: string, + detached?: boolean, func: (argv: Array, ctx: ConfigT, args: Object) => ?Promise, options?: Array<{ name: string, From 94d8bba8e1cbd768526649a2965e8fd09e542c3f Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 13:19:11 +0200 Subject: [PATCH 33/43] Resolve conflicts --- yarn.lock | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/yarn.lock b/yarn.lock index 48086f37b..14e440414 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4353,6 +4353,14 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + flat-cache@^1.2.1: version "1.3.0" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.0.tgz#d3030b32b38154f4e3b7e9c709f490f7ef97c481" @@ -6109,6 +6117,13 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + lodash._reinterpolate@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" @@ -7303,6 +7318,13 @@ p-limit@^2.0.0: dependencies: p-try "^2.0.0" +p-limit@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.1.tgz#aa07a788cc3151c939b5131f63570f0dd2009537" + integrity sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg== + dependencies: + p-try "^2.0.0" + p-locate@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" @@ -7316,6 +7338,13 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-map-series@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca" @@ -7477,6 +7506,11 @@ path-exists@^3.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" From beca41bc300d1a8f9704af67eefd52ef095c44f7 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 13:28:07 +0200 Subject: [PATCH 34/43] Fix remainig uses or root and get rid of cwd --- packages/cli/src/commands/init/initCompat.ts | 30 ++++++++++++-------- packages/cli/src/commands/init/template.ts | 4 +-- packages/cli/src/tools/packageManager.ts | 8 ++---- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/packages/cli/src/commands/init/initCompat.ts b/packages/cli/src/commands/init/initCompat.ts index 15c475e9f..fc9592f2c 100644 --- a/packages/cli/src/commands/init/initCompat.ts +++ b/packages/cli/src/commands/init/initCompat.ts @@ -56,7 +56,6 @@ async function generateProject( const pkgJson = require('react-native/package.json'); const reactVersion = pkgJson.peerDependencies.react; - PackageManager.setProjectDir(destinationRoot); await createProjectFromTemplate( destinationRoot, newProjectName, @@ -64,19 +63,26 @@ async function generateProject( ); logger.info('Adding required dependencies'); - await PackageManager.install([`react@${reactVersion}`]); + await PackageManager.install([`react@${reactVersion}`], { + root: destinationRoot, + }); logger.info('Adding required dev dependencies'); - await PackageManager.installDev([ - '@babel/core', - '@babel/runtime', - '@react-native-community/eslint-config', - 'eslint', - 'jest', - 'babel-jest', - 'metro-react-native-babel-preset', - `react-test-renderer@${reactVersion}`, - ]); + await PackageManager.installDev( + [ + '@babel/core', + '@babel/runtime', + '@react-native-community/eslint-config', + 'eslint', + 'jest', + 'babel-jest', + 'metro-react-native-babel-preset', + `react-test-renderer@${reactVersion}`, + ], + { + root: destinationRoot, + }, + ); addJestToPackageJson(destinationRoot); diff --git a/packages/cli/src/commands/init/template.ts b/packages/cli/src/commands/init/template.ts index 683d24c71..02e6831ba 100644 --- a/packages/cli/src/commands/init/template.ts +++ b/packages/cli/src/commands/init/template.ts @@ -14,14 +14,14 @@ export type TemplateConfig = { export function installTemplatePackage( templateName: string, - cwd: string, + root: string, npm?: boolean, ) { logger.debug(`Installing template from ${templateName}`); return PackageManager.install([templateName], { preferYarn: !npm, silent: true, - cwd, + root, }); } diff --git a/packages/cli/src/tools/packageManager.ts b/packages/cli/src/tools/packageManager.ts index e9f0bd783..bfdf40094 100644 --- a/packages/cli/src/tools/packageManager.ts +++ b/packages/cli/src/tools/packageManager.ts @@ -5,7 +5,6 @@ import {getYarnVersionIfAvailable, isProjectUsingYarn} from './yarn'; type Options = { preferYarn?: boolean; silent?: boolean; - cwd?: string; root: string; }; @@ -38,12 +37,11 @@ function configurePackageManager( function executeCommand( command: string, args: Array, - options?: Options, + options: Options, ) { return execa(command, args, { - stdio: - options && options.silent && !logger.isVerbose() ? 'pipe' : 'inherit', - cwd: options && options.cwd, + stdio: options.silent && !logger.isVerbose() ? 'pipe' : 'inherit', + cwd: options.root, }); } From cc8c80c9045d52b87f59b7d01882eb8fb166d886 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 13:45:42 +0200 Subject: [PATCH 35/43] Update paths --- packages/cli/src/commands/init/init.ts | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/commands/init/init.ts b/packages/cli/src/commands/init/init.ts index 34620aa71..afb867b02 100644 --- a/packages/cli/src/commands/init/init.ts +++ b/packages/cli/src/commands/init/init.ts @@ -49,11 +49,13 @@ function doesDirectoryExist(dir: string) { function getProjectDirectory({ projectName, directory, + root, }: { projectName: string; directory: string; + root: string; }): string { - return path.relative(process.cwd(), directory || projectName); + return path.relative(root, directory || projectName); } async function setProjectDirectory(directory: string) { @@ -86,6 +88,8 @@ async function setProjectDirectory(directory: string) { error, ); } + + return process.cwd(); } function adjustNameIfUrl(name: string, cwd: string) { @@ -111,7 +115,7 @@ async function createFromTemplate({ logger.debug('Initializing new project'); logger.log(banner); - await setProjectDirectory(directory); + const projectDirectory = await setProjectDirectory(directory); const Loader = getLoader(); const loader = new Loader({text: 'Downloading template'}); @@ -151,7 +155,12 @@ async function createFromTemplate({ loader.succeed(); } - await installDependencies({projectName, npm, loader, directory}); + await installDependencies({ + projectName, + npm, + loader, + root: projectDirectory, + }); } catch (e) { loader.fail(); throw new Error(e); @@ -164,19 +173,19 @@ async function installDependencies({ projectName, npm, loader, - directory, + root, }: { projectName: string; npm?: boolean; loader: ora.Ora; - directory: string; + root: string; }) { loader.start('Installing dependencies'); await PackageManager.installAll({ preferYarn: !npm, silent: true, - root: directory, + root, }); if (process.platform === 'darwin') { From 66614213932b1b755a2d61739496f32789f30ee3 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 13:48:22 +0200 Subject: [PATCH 36/43] Remove unused func --- packages/cli/src/commands/init/init.ts | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/packages/cli/src/commands/init/init.ts b/packages/cli/src/commands/init/init.ts index afb867b02..3b524fa24 100644 --- a/packages/cli/src/commands/init/init.ts +++ b/packages/cli/src/commands/init/init.ts @@ -46,18 +46,6 @@ function doesDirectoryExist(dir: string) { return fs.existsSync(dir); } -function getProjectDirectory({ - projectName, - directory, - root, -}: { - projectName: string; - directory: string; - root: string; -}): string { - return path.relative(root, directory || projectName); -} - async function setProjectDirectory(directory: string) { const directoryExists = doesDirectoryExist(directory); if (directoryExists) { @@ -226,7 +214,7 @@ export default (async function initialize( [projectName]: Array, options: Options, ) { - const rootFolder = process.cwd(); + const root = process.cwd(); validateProjectName(projectName); @@ -236,15 +224,12 @@ export default (async function initialize( */ const version: string = minimist(process.argv).version || DEFAULT_VERSION; - const directoryName = getProjectDirectory({ - projectName, - directory: options.directory || projectName, - }); + const directoryName = path.relative(root, options.directory || projectName); try { await createProject(projectName, directoryName, version, options); - const projectFolder = path.join(rootFolder, projectName); + const projectFolder = path.join(root, projectName); printRunInstructions(projectFolder, projectName); } catch (e) { logger.error(e.message); From 781c0e623ffefcd3606ae15d323fa6e4c87ec132 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 13:55:35 +0200 Subject: [PATCH 37/43] Update templates.ts --- packages/cli/src/tools/generator/templates.ts | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/packages/cli/src/tools/generator/templates.ts b/packages/cli/src/tools/generator/templates.ts index 4ff6370af..c538944fb 100644 --- a/packages/cli/src/tools/generator/templates.ts +++ b/packages/cli/src/tools/generator/templates.ts @@ -71,7 +71,7 @@ async function createFromRemoteTemplate( // Check if the template exists logger.info(`Fetching template ${installPackage}...`); try { - await PackageManager.install([installPackage]); + await PackageManager.install([installPackage], {root: destPath}); const templatePath = path.resolve('node_modules', templateName); copyProjectTemplateAndReplace(templatePath, destPath, newProjectName, { // Every template contains a dummy package.json file included @@ -84,12 +84,12 @@ async function createFromRemoteTemplate( 'devDependencies.json', ], }); - await installTemplateDependencies(templatePath); - await installTemplateDevDependencies(templatePath); + await installTemplateDependencies(templatePath, destPath); + await installTemplateDevDependencies(templatePath, destPath); } finally { // Clean up the temp files try { - await PackageManager.uninstall([templateName]); + await PackageManager.uninstall([templateName], {root: destPath}); } catch (err) { // Not critical but we still want people to know and report // if this the clean up fails. @@ -101,7 +101,7 @@ async function createFromRemoteTemplate( } } -async function installTemplateDependencies(templatePath: string) { +async function installTemplateDependencies(templatePath: string, root: string) { // dependencies.json is a special file that lists additional dependencies // that are required by this template const dependenciesJsonPath = path.resolve(templatePath, 'dependencies.json'); @@ -122,12 +122,15 @@ async function installTemplateDependencies(templatePath: string) { const dependenciesToInstall = Object.keys(dependencies).map( depName => `${depName}@${dependencies[depName]}`, ); - await PackageManager.install(dependenciesToInstall); + await PackageManager.install(dependenciesToInstall, {root}); logger.info("Linking native dependencies into the project's build files..."); - execSync('react-native link', {stdio: 'inherit'}); + execSync('react-native link', {cwd: root, stdio: 'inherit'}); } -async function installTemplateDevDependencies(templatePath: string) { +async function installTemplateDevDependencies( + templatePath: string, + root: string, +) { // devDependencies.json is a special file that lists additional develop dependencies // that are required by this template const devDependenciesJsonPath = path.resolve( @@ -152,7 +155,7 @@ async function installTemplateDevDependencies(templatePath: string) { const dependenciesToInstall = Object.keys(dependencies).map( depName => `${depName}@${dependencies[depName]}`, ); - await PackageManager.installDev(dependenciesToInstall); + await PackageManager.installDev(dependenciesToInstall, {root}); } export {createProjectFromTemplate}; From 46b0cd39cf958c6e8a78f823eba09401fa4f7559 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 14:06:29 +0200 Subject: [PATCH 38/43] Fix unit tests --- .../commands/init/__tests__/template.test.ts | 2 +- .../tools/__tests__/packageManager-test.ts | 28 ++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/packages/cli/src/commands/init/__tests__/template.test.ts b/packages/cli/src/commands/init/__tests__/template.test.ts index 472e2e864..a727d44aa 100644 --- a/packages/cli/src/commands/init/__tests__/template.test.ts +++ b/packages/cli/src/commands/init/__tests__/template.test.ts @@ -26,7 +26,7 @@ test('installTemplatePackage', async () => { expect(PackageManger.install).toHaveBeenCalledWith([TEMPLATE_NAME], { preferYarn: false, silent: true, - cwd: TEMPLATE_SOURCE_DIR, + root: TEMPLATE_SOURCE_DIR, }); }); diff --git a/packages/cli/src/tools/__tests__/packageManager-test.ts b/packages/cli/src/tools/__tests__/packageManager-test.ts index 8bde1bbd2..1339f9c2f 100644 --- a/packages/cli/src/tools/__tests__/packageManager-test.ts +++ b/packages/cli/src/tools/__tests__/packageManager-test.ts @@ -5,8 +5,8 @@ import {logger} from '@react-native-community/cli-tools'; import * as PackageManager from '../packageManager'; const PACKAGES = ['react', 'react-native']; -const EXEC_OPTS = {stdio: 'inherit'}; const PROJECT_ROOT = '/some/dir'; +const EXEC_OPTS = {stdio: 'inherit', cwd: PROJECT_ROOT}; afterEach(() => { jest.resetAllMocks(); @@ -22,13 +22,13 @@ describe('yarn', () => { }); it('should install', () => { - PackageManager.install(PACKAGES, {preferYarn: true}); + PackageManager.install(PACKAGES, {preferYarn: true, root: PROJECT_ROOT}); expect(execa).toHaveBeenCalledWith('yarn', ['add', ...PACKAGES], EXEC_OPTS); }); it('should installDev', () => { - PackageManager.installDev(PACKAGES, {preferYarn: true}); + PackageManager.installDev(PACKAGES, {preferYarn: true, root: PROJECT_ROOT}); expect(execa).toHaveBeenCalledWith( 'yarn', @@ -38,7 +38,7 @@ describe('yarn', () => { }); it('should uninstall', () => { - PackageManager.uninstall(PACKAGES, {preferYarn: true}); + PackageManager.uninstall(PACKAGES, {preferYarn: true, root: PROJECT_ROOT}); expect(execa).toHaveBeenCalledWith( 'yarn', @@ -50,7 +50,7 @@ describe('yarn', () => { describe('npm', () => { it('should install', () => { - PackageManager.install(PACKAGES, {preferYarn: false}); + PackageManager.install(PACKAGES, {preferYarn: false, root: PROJECT_ROOT}); expect(execa).toHaveBeenCalledWith( 'npm', @@ -60,7 +60,10 @@ describe('npm', () => { }); it('should installDev', () => { - PackageManager.installDev(PACKAGES, {preferYarn: false}); + PackageManager.installDev(PACKAGES, { + preferYarn: false, + root: PROJECT_ROOT, + }); expect(execa).toHaveBeenCalledWith( 'npm', @@ -70,7 +73,7 @@ describe('npm', () => { }); it('should uninstall', () => { - PackageManager.uninstall(PACKAGES, {preferYarn: false}); + PackageManager.uninstall(PACKAGES, {preferYarn: false, root: PROJECT_ROOT}); expect(execa).toHaveBeenCalledWith( 'npm', @@ -82,7 +85,7 @@ describe('npm', () => { it('should use npm if yarn is not available', () => { jest.spyOn(yarn, 'getYarnVersionIfAvailable').mockImplementation(() => false); - PackageManager.install(PACKAGES, {preferYarn: true}); + PackageManager.install(PACKAGES, {preferYarn: true, root: PROJECT_ROOT}); expect(execa).toHaveBeenCalledWith( 'npm', @@ -94,8 +97,7 @@ it('should use npm if yarn is not available', () => { it('should use npm if project is not using yarn', () => { jest.spyOn(yarn, 'isProjectUsingYarn').mockImplementation(() => false); - PackageManager.setProjectDir(PROJECT_ROOT); - PackageManager.install(PACKAGES); + PackageManager.install(PACKAGES, {root: PROJECT_ROOT}); expect(execa).toHaveBeenCalledWith( 'npm', @@ -109,8 +111,7 @@ it('should use yarn if project is using yarn', () => { jest.spyOn(yarn, 'getYarnVersionIfAvailable').mockImplementation(() => true); jest.spyOn(yarn, 'isProjectUsingYarn').mockImplementation(() => true); - PackageManager.setProjectDir(PROJECT_ROOT); - PackageManager.install(PACKAGES); + PackageManager.install(PACKAGES, {root: PROJECT_ROOT}); expect(execa).toHaveBeenCalledWith('yarn', ['add', ...PACKAGES], EXEC_OPTS); expect(yarn.isProjectUsingYarn).toHaveBeenCalledWith(PROJECT_ROOT); @@ -125,10 +126,11 @@ test.each([[false, 'pipe'], [true, 'inherit']])( jest.spyOn(yarn, 'isProjectUsingYarn').mockImplementation(() => true); jest.spyOn(logger, 'isVerbose').mockImplementation(() => isVerbose); - PackageManager.install(PACKAGES, {silent: true}); + PackageManager.install(PACKAGES, {root: PROJECT_ROOT, silent: true}); expect(execa).toHaveBeenCalledWith('yarn', ['add', ...PACKAGES], { stdio: stdioType, + cwd: PROJECT_ROOT, }); }, ); From 5033e50671f1c1b61ac62c1fd7aec28820b21ebf Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 15:03:39 +0200 Subject: [PATCH 39/43] Better logger --- packages/cli/src/cliEntry.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/cliEntry.js b/packages/cli/src/cliEntry.js index 25a9c403e..0f6f3fbfb 100644 --- a/packages/cli/src/cliEntry.js +++ b/packages/cli/src/cliEntry.js @@ -170,17 +170,15 @@ async function setupAndRun() { } } - // when we run `config`, we don't want to output anything to the console. We - // expect it to return valid JSON - if (process.argv.includes('config')) { - logger.disable(); - } - - logger.enable(); - detachedCommands.forEach(addCommand); try { + // when we run `config`, we don't want to output anything to the console. We + // expect it to return valid JSON + if (process.argv.includes('config')) { + logger.disable(); + } + const ctx = loadConfig(); [...projectCommands, ...ctx.commands].forEach(command => @@ -188,6 +186,8 @@ async function setupAndRun() { ); } catch (e) {} + logger.enable(); + commander.parse(process.argv); if (commander.rawArgs.length === 2) { From cc4b5bf10f7e163a7de3744eca895452ffd1fa20 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 15:16:18 +0200 Subject: [PATCH 40/43] Debug --- packages/cli/src/cliEntry.js | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/cliEntry.js b/packages/cli/src/cliEntry.js index 0f6f3fbfb..5a0f2f9dd 100644 --- a/packages/cli/src/cliEntry.js +++ b/packages/cli/src/cliEntry.js @@ -151,6 +151,9 @@ async function run() { } async function setupAndRun() { + // Commander is not available yet + logger.setVerbose(process.argv.includes('--verbose')); + // We only have a setup script for UNIX envs currently if (process.platform !== 'win32') { const scriptName = 'setup_env.sh'; @@ -181,12 +184,18 @@ async function setupAndRun() { const ctx = loadConfig(); + logger.enable(); + [...projectCommands, ...ctx.commands].forEach(command => addCommand(command, ctx), ); - } catch (e) {} - - logger.enable(); + } catch (e) { + logger.enable(); + logger.debug(e.message); + logger.debug( + 'Failed to load configuration of your project. Only a subset of commands will be available.', + ); + } commander.parse(process.argv); @@ -200,8 +209,6 @@ async function setupAndRun() { if (commander.args.length === 0 && commander.rawArgs.includes('--version')) { console.log(pkgJson.version); } - - logger.setVerbose(commander.verbose); } export default { From 7402931bffaa044b9595acda0e31cfcad0d123e8 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 15:24:15 +0200 Subject: [PATCH 41/43] Add deprecations --- packages/platform-android/native_modules.gradle | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/platform-android/native_modules.gradle b/packages/platform-android/native_modules.gradle index 5264eeacd..43056305f 100644 --- a/packages/platform-android/native_modules.gradle +++ b/packages/platform-android/native_modules.gradle @@ -211,11 +211,17 @@ class ReactNativeModules { def autoModules = new ReactNativeModules(logger) -ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings -> +ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings, String root = null -> + if (root != null) { + logger.warn("${ReactNativeModules.LOG_PREFIX}Passing custom root to is deprecated. CLI detects root automatically now"); + } autoModules.addReactNativeModuleProjects(defaultSettings) } -ext.applyNativeModulesAppBuildGradle = { Project project -> +ext.applyNativeModulesAppBuildGradle = { Project project, String root = null -> + if (root != null) { + logger.warn("${ReactNativeModules.LOG_PREFIX}Passing custom root to is deprecated. CLI detects root automatically now"); + } autoModules.addReactNativeModuleDependencies(project) def generatedSrcDir = new File(buildDir, "generated/rncli/src/main/java") From 90bacbce3116bb1cfcb8740cffb341e3fac2ee81 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 15:24:59 +0200 Subject: [PATCH 42/43] Fix a typo --- packages/platform-android/native_modules.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/platform-android/native_modules.gradle b/packages/platform-android/native_modules.gradle index 43056305f..09cd69e47 100644 --- a/packages/platform-android/native_modules.gradle +++ b/packages/platform-android/native_modules.gradle @@ -213,14 +213,14 @@ def autoModules = new ReactNativeModules(logger) ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings, String root = null -> if (root != null) { - logger.warn("${ReactNativeModules.LOG_PREFIX}Passing custom root to is deprecated. CLI detects root automatically now"); + logger.warn("${ReactNativeModules.LOG_PREFIX}Passing custom root is deprecated. CLI detects root automatically now"); } autoModules.addReactNativeModuleProjects(defaultSettings) } ext.applyNativeModulesAppBuildGradle = { Project project, String root = null -> if (root != null) { - logger.warn("${ReactNativeModules.LOG_PREFIX}Passing custom root to is deprecated. CLI detects root automatically now"); + logger.warn("${ReactNativeModules.LOG_PREFIX}Passing custom root is deprecated. CLI detects root automatically now"); } autoModules.addReactNativeModuleDependencies(project) From d0bd034fe699d9d0907bd9fa26d00d00f398b3c8 Mon Sep 17 00:00:00 2001 From: grabbou Date: Thu, 10 Oct 2019 15:28:31 +0200 Subject: [PATCH 43/43] Better deprecation message --- packages/platform-android/native_modules.gradle | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/platform-android/native_modules.gradle b/packages/platform-android/native_modules.gradle index 09cd69e47..2369c2bdc 100644 --- a/packages/platform-android/native_modules.gradle +++ b/packages/platform-android/native_modules.gradle @@ -213,7 +213,8 @@ def autoModules = new ReactNativeModules(logger) ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings, String root = null -> if (root != null) { - logger.warn("${ReactNativeModules.LOG_PREFIX}Passing custom root is deprecated. CLI detects root automatically now"); + logger.warn("${ReactNativeModules.LOG_PREFIX}Passing custom root is deprecated. CLI detects root automatically now."); + logger.warn("${ReactNativeModules.LOG_PREFIX}Please remove second argument to `applyNativeModulesSettingsGradle`."); } autoModules.addReactNativeModuleProjects(defaultSettings) } @@ -221,6 +222,7 @@ ext.applyNativeModulesSettingsGradle = { DefaultSettings defaultSettings, String ext.applyNativeModulesAppBuildGradle = { Project project, String root = null -> if (root != null) { logger.warn("${ReactNativeModules.LOG_PREFIX}Passing custom root is deprecated. CLI detects root automatically now"); + logger.warn("${ReactNativeModules.LOG_PREFIX}Please remove second argument to `applyNativeModulesAppBuildGradle`."); } autoModules.addReactNativeModuleDependencies(project)