react_native_util 0.2.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bac5388f9ceda5e72b4a54c717f742c5a56c07f0a7b7489a9cac567469cfe728
4
- data.tar.gz: aea447d8cf31bb2d9feb5b4eb42ec8d869071ced5036f722049fabd38f17b00b
3
+ metadata.gz: 7f874dfbe6f26ca09e59e9392f1e6591d09148b6a34aba766a41feea3bb2957e
4
+ data.tar.gz: 6ccfddce4c25414ef398924bb426dc0191851fb40c1ad6477e19f1eb3970b6cf
5
5
  SHA512:
6
- metadata.gz: e3f3375ad84f084472f36eeac3ae9a6ce2a0fda11a88bb32055a45940c7c39919daea4c5056b75650c130e509f964751e3ae70aeac0b445ef886eefad8f6fc1f
7
- data.tar.gz: 89fcadbf7b2e9db331dd7bab9e3d066a1e06b4c2bd9117560ba79b58c5b871a1a658bf6bbe7bcd5ff6f3d60330d23202e71a79d94b78caa76a8491334aef9179
6
+ metadata.gz: 798ac753cc2ca53970ee8def6a65f24159a69b300e1259864ee59bc9d888aed2323d282bf053e7a78dd9d57f1f4f267d56b471ab0e0bb02ea365aff2ff4e9f13
7
+ data.tar.gz: bfd1a390de9180aed09a3a7da175a938a25743c99233937b499a21eab4c04961d6d35553f1676c44af4f3db3b89705f762dbb377c434b55ff8d602365a5dfaf4
data/README.md CHANGED
@@ -13,9 +13,13 @@ Community utility CLI for React Native projects.
13
13
 
14
14
  _macOS required_
15
15
 
16
+ It's not necessary to install yarn or react-native-cli separately when
17
+ installing from the Homebrew tap with `brew install jdee/tap/react_native_util`.
18
+ They will be installed as required dependencies. If they are not present when
19
+ running from RubyGems, the react_pod command will fail.
16
20
  ```bash
17
- brew install yarn # Not necessary if installing from Homebrew tap
18
- npm install -g react-native-cli
21
+ brew install yarn
22
+ brew install react-native-cli
19
23
  ```
20
24
 
21
25
  ## Installation
@@ -56,35 +60,35 @@ git status
56
60
 
57
61
  _Typical command output:_
58
62
  ```
59
- 2019-05-12T11:42:03-07:00 react_native_util react_pod v0.2.2
60
- [✔] yarn install success in 10.9 s
61
- 2019-05-12T11:42:14-07:00 Darwin 18.5.0 x86_64
62
- 2019-05-12T11:42:14-07:00 Ruby 2.6.3: ~/.rvm/rubies/ruby-2.6.3/bin/ruby
63
- 2019-05-12T11:42:14-07:00 RubyGems 3.0.3: ~/.rvm/rubies/ruby-2.6.3/bin/gem
64
- 2019-05-12T11:42:14-07:00 Bundler 1.17.2: ~/.rvm/gems/ruby-2.6.3/bin/bundle
65
- 2019-05-12T11:42:14-07:00 react-native-cli: /usr/local/bin/react-native
66
- 2019-05-12T11:42:14-07:00 react-native-cli: 2.0.1
67
- 2019-05-12T11:42:14-07:00 react-native: 0.59.8
68
- 2019-05-12T11:42:15-07:00 yarn 1.16.0: /usr/local/bin/yarn
69
- 2019-05-12T11:42:15-07:00 cocoapods 1.6.1: ~/.rvm/gems/ruby-2.6.3/bin/pod
70
- 2019-05-12T11:42:15-07:00 cocoapods-core: 1.6.1
71
- 2019-05-12T11:42:15-07:00 package.json:
72
- 2019-05-12T11:42:15-07:00 app name: "TestApp"
73
- 2019-05-12T11:42:15-07:00 Found Xcode project at ~/github/jdee/react_native_util/examples/TestApp/ios/TestApp.xcodeproj
74
- 2019-05-12T11:42:15-07:00 Dependencies:
75
- 2019-05-12T11:42:15-07:00 react-native-webview
76
- 2019-05-12T11:42:15-07:00 Unlinking dependencies
77
- [✔] react-native unlink react-native-webview success in 0.7 s
78
- 2019-05-12T11:42:16-07:00 Removing Libraries from TestApp
79
- 2019-05-12T11:42:16-07:00 Removing Libraries from TestAppTests
80
- 2019-05-12T11:42:16-07:00 Removing Libraries group
81
- 2019-05-12T11:42:16-07:00 Generating ios/Podfile
82
- 2019-05-12T11:42:16-07:00 Linking dependencies
63
+ 2019-05-12T15:37:50-07:00 react_native_util react_pod v0.3.0
64
+ [✔] yarn install success in 7.2 s
65
+ 2019-05-12T15:37:57-07:00 Darwin 18.5.0 x86_64
66
+ 2019-05-12T15:37:57-07:00 Ruby 2.6.3: ~/.rvm/rubies/ruby-2.6.3/bin/ruby
67
+ 2019-05-12T15:37:57-07:00 RubyGems 3.0.3: ~/.rvm/rubies/ruby-2.6.3/bin/gem
68
+ 2019-05-12T15:37:57-07:00 Bundler 1.17.2: ~/.rvm/gems/ruby-2.6.3/bin/bundle
69
+ 2019-05-12T15:37:57-07:00 react-native-cli: /usr/local/bin/react-native
70
+ 2019-05-12T15:37:57-07:00 react-native-cli: 2.0.1
71
+ 2019-05-12T15:37:57-07:00 react-native: 0.59.8
72
+ 2019-05-12T15:37:58-07:00 yarn 1.16.0: /usr/local/bin/yarn
73
+ 2019-05-12T15:37:58-07:00 cocoapods 1.6.1: ~/.rvm/gems/ruby-2.6.3/bin/pod
74
+ 2019-05-12T15:37:58-07:00 cocoapods-core: 1.6.1
75
+ 2019-05-12T15:37:58-07:00 package.json:
76
+ 2019-05-12T15:37:58-07:00 app name: "TestApp"
77
+ 2019-05-12T15:37:58-07:00 Found Xcode project at ~/github/jdee/react_native_util/examples/TestApp/ios/TestApp.xcodeproj
78
+ 2019-05-12T15:37:58-07:00 Dependencies:
79
+ 2019-05-12T15:37:58-07:00 react-native-webview
80
+ 2019-05-12T15:37:58-07:00 Unlinking dependencies
81
+ [✔] react-native unlink react-native-webview success in 0.6 s
82
+ 2019-05-12T15:37:59-07:00 Removing Libraries from TestApp
83
+ 2019-05-12T15:37:59-07:00 Removing Libraries from TestAppTests
84
+ 2019-05-12T15:37:59-07:00 Removing Libraries group
85
+ 2019-05-12T15:37:59-07:00 Generating ios/Podfile
86
+ 2019-05-12T15:37:59-07:00 Linking dependencies
83
87
  [✔] react-native link react-native-webview success in 0.5 s
84
- 2019-05-12T11:42:17-07:00 Generating Pods project and ios/TestApp.xcworkspace
85
- [✔] pod install success in 8.2 s
86
- 2019-05-12T11:42:25-07:00 Conversion complete ✅
87
- 2019-05-12T11:42:25-07:00 $ open ios/TestApp.xcworkspace
88
+ 2019-05-12T15:37:59-07:00 Generating Pods project and ios/TestApp.xcworkspace
89
+ [✔] pod install success in 12.2 s
90
+ 2019-05-12T15:38:12-07:00 Conversion complete ✅
91
+ 2019-05-12T15:38:12-07:00 $ open ios/TestApp.xcworkspace
88
92
  ```
89
93
 
90
94
  ## Rake task
@@ -112,6 +116,10 @@ ReactNativeUtil::Rake::ReactPodTask.new(
112
116
  require 'react_native_util/converter'
113
117
 
114
118
  Dir.chdir '/path/to/rn/project' do
115
- ReactNativeUtil::Converter.new(repo_update: true).convert_to_react_pod!
119
+ begin
120
+ ReactNativeUtil::Converter.new(repo_update: true).convert_to_react_pod!
121
+ rescue ReactNativeUtil::BaseException => e
122
+ puts "Error from #convert_to_react_pod!: #{e.message}"
123
+ end
116
124
  end
117
125
  ```
@@ -11,6 +11,9 @@ target '<%= app_name %>' do
11
11
  ]
12
12
  pod 'yoga', path: '../node_modules/react-native/ReactCommon/yoga'
13
13
  pod 'Folly', podspec: '../node_modules/react-native/third-party-podspecs/Folly.podspec'
14
+
15
+ # --- react-native link adds pods below this line. ---
16
+
14
17
  end
15
18
 
16
19
  <% if test_target %>
@@ -2,49 +2,29 @@ require 'cocoapods-core'
2
2
  require 'erb'
3
3
  require 'json'
4
4
  require 'rubygems'
5
- require 'tmpdir'
6
- require 'tty/platform'
7
- require 'xcodeproj'
8
- require_relative 'util'
5
+ require_relative 'project'
9
6
 
10
7
  module ReactNativeUtil
11
8
  # Class to perform conversion operations.
12
9
  class Converter
13
10
  include Util
14
11
 
15
- # [Array<String>] Xcode projects from react-native that may be in the Libraries group
16
- DEFAULT_DEPENDENCIES = %w[
17
- ART
18
- React
19
- RCTActionSheet
20
- RCTAnimation
21
- RCTBlob
22
- RCTCameraRoll
23
- RCTGeolocation
24
- RCTImage
25
- RCTLinking
26
- RCTNetwork
27
- RCTPushNotification
28
- RCTSettings
29
- RCTTest
30
- RCTText
31
- RCTVibration
32
- RCTWebSocket
33
- ]
34
-
35
12
  # [String] Path to the Podfile template
36
13
  PODFILE_TEMPLATE_PATH = File.expand_path '../assets/templates/Podfile.erb', __dir__
37
14
 
15
+ REQUIRED_COMMANDS = [:yarn, 'react-native' => 'react-native-cli']
16
+
38
17
  # [Hash] Contents of ./package.json
39
18
  attr_reader :package_json
40
19
 
41
20
  # [String] Full path to Xcode project
42
21
  attr_reader :xcodeproj_path
43
22
 
44
- # [Xcodeproj::Project] Contents of the project at xcodproj_path
45
- attr_reader :xcodeproj
23
+ # [Project] Contents of the project at xcodeproj_path
24
+ attr_reader :project
46
25
 
47
26
  attr_reader :options
27
+ attr_reader :react_project
48
28
  attr_reader :react_podspec
49
29
 
50
30
  def initialize(repo_update: nil)
@@ -56,9 +36,27 @@ module ReactNativeUtil
56
36
  end
57
37
  end
58
38
 
59
- # Convert project to use React pod
60
- # @raise ConversionError on failure
39
+ # Convert project to use React pod. Expects the app's package.json in the
40
+ # current directory.
41
+ #
42
+ # require 'react_native_util/converter'
43
+ #
44
+ # Dir.chdir '/path/to/rn/project' do
45
+ # begin
46
+ # ReactNativeUtil::Converter.new(repo_update: true).convert_to_react_pod!
47
+ # rescue ReactNativeUtil::BaseException => e
48
+ # # All exceptions generated by this gem inherit from
49
+ # # ReactNativeUtil::BaseException.
50
+ # puts "Error from #convert_to_react_pod!: #{e.message}"
51
+ # end
52
+ # end
53
+ #
54
+ # @raise ConversionError on conversion failure
55
+ # @raise ExecutionError on generic command failure
56
+ # @raise Errno::ENOENT if a required command is not present
61
57
  def convert_to_react_pod!
58
+ validate_commands! REQUIRED_COMMANDS
59
+
62
60
  # Make sure no uncommitted changes
63
61
  check_repo_status!
64
62
 
@@ -75,7 +73,7 @@ module ReactNativeUtil
75
73
  load_xcodeproj!
76
74
  log "Found Xcode project at #{xcodeproj_path}"
77
75
 
78
- if libraries_group.nil?
76
+ if project.libraries_group.nil?
79
77
  log "Libraries group not found in #{xcodeproj_path}. No conversion necessary."
80
78
  exit 0
81
79
  end
@@ -87,35 +85,37 @@ module ReactNativeUtil
87
85
  exit 1
88
86
  end
89
87
 
88
+ project.validate_app_target!
89
+
90
90
  load_react_podspec!
91
91
 
92
92
  # 2. Detect native dependencies in Libraries group.
93
93
  log 'Dependencies:'
94
- dependencies.each { |d| log " #{d}" }
94
+ project.dependencies.each { |d| log " #{d}" }
95
95
 
96
96
  # Save for after Libraries removed.
97
- deps_to_add = dependencies
97
+ deps_to_add = project.dependencies
98
98
 
99
99
  # 3. Run react-native unlink for each one.
100
100
  log 'Unlinking dependencies'
101
- dependencies.each do |dep|
101
+ project.dependencies.each do |dep|
102
102
  run_command_with_spinner! 'react-native', 'unlink', dep, log: File.join(Dir.tmpdir, "react-native-unlink-#{dep}.log")
103
103
  end
104
104
 
105
105
  # reload after react-native unlink
106
106
  load_xcodeproj!
107
+ load_react_project!
107
108
 
108
109
  # 4a. Add Start Packager script
109
- validate_app_target!
110
- add_packager_script
110
+ project.add_packager_script_from react_project
111
111
 
112
112
  # Make a note of pod subspecs to replace Libraries group
113
113
  load_subspecs_from_libraries
114
114
 
115
115
  # 4b. Remove Libraries group from Xcode project.
116
- remove_libraries_group_from_project!
116
+ project.remove_libraries_group
117
117
 
118
- xcodeproj.save
118
+ project.save
119
119
 
120
120
  # 5. Generate boilerplate Podfile.
121
121
  generate_podfile!
@@ -207,8 +207,9 @@ module ReactNativeUtil
207
207
  # Load the project at @xcodeproj_path into @xcodeproj
208
208
  # @raise ConversionError on failure
209
209
  def load_xcodeproj!
210
- @xcodeproj = nil # in case of exception on reopen
211
- @xcodeproj = Xcodeproj::Project.open xcodeproj_path
210
+ @project = nil # in case of exception on reopen
211
+ @project = Project.open xcodeproj_path
212
+ @project.app_name = app_name
212
213
  rescue Errno::ENOENT
213
214
  raise ConversionError, "Failed to open #{xcodeproj_path}. File not found."
214
215
  rescue Xcodeproj::PlainInformative => e
@@ -226,72 +227,9 @@ module ReactNativeUtil
226
227
  # rubocop: enable Security/Eval
227
228
  end
228
229
 
229
- # A representation of the Libraries group (if any) from the Xcode project.
230
- # @return the Libraries group
231
- def libraries_group
232
- xcodeproj['Libraries']
233
- end
234
-
235
- # Remove the Libraries group from the xcodeproj in memory.
236
- # Resets @libraries_group to nil as well.
237
- def remove_libraries_group_from_project!
238
- # Remove links against these static libraries
239
- xcodeproj.targets.reject { |t| t.name =~ /-tvOS/ }.each do |t|
240
- remove_libraries_from_target t
241
- end
242
-
243
- log 'Removing Libraries group'
244
- libraries_group.remove_from_project
245
- end
246
-
247
- def remove_libraries_from_target(target)
248
- log "Removing Libraries from #{target.name}"
249
- to_remove = target.frameworks_build_phase.files.select do |file|
250
- path = file.file_ref.pretty_print
251
- next false unless /^lib(.+)\.a$/.match?(path)
252
-
253
- static_libs.include?(path)
254
- end
255
-
256
- to_remove.each { |f| target.frameworks_build_phase.remove_build_file f }
257
- end
258
-
259
- # A list of external dependencies from NPM requiring react-native link.
260
- # @return [Array<String>] a list of NPM package names
261
- def dependencies
262
- return [] if libraries_group.nil?
263
-
264
- dependency_paths.map do |path|
265
- # Find the root above the ios/*.xcodeproj under node_modules
266
- root = File.expand_path '../..', path
267
- File.basename root
268
- end
269
- end
270
-
271
- # Paths to Xcode projects in the Libraries group from external deps.
272
- # @return [Array<String>] a list of absolute paths to Xcode projects
273
- def dependency_paths
274
- return [] if libraries_group.nil?
275
-
276
- paths = libraries_group.children.reject { |c| DEFAULT_DEPENDENCIES.include?(c.name.sub(/\.xcodeproj$/, '')) }.map(&:path)
277
- paths.map { |p| File.expand_path p, File.join(Dir.pwd, 'ios') }
278
- end
279
-
280
- def library_roots
281
- libraries_group.children.map do |library|
282
- File.basename(library.path).sub(/\.xcodeproj$/, '')
283
- end
284
- end
285
-
286
- # All static libraries from the Libraries group
287
- # @return [Array<String>] an array of filenames
288
- def static_libs
289
- library_roots.map { |root| "lib#{root}.a" }
290
- end
291
-
292
230
  def load_subspecs_from_libraries
293
- roots = library_roots - %w[React]
294
- @subspecs_from_libraries = roots.select { |r| DEFAULT_DEPENDENCIES.include?(r) }.map do |root|
231
+ roots = project.library_roots - %w[React]
232
+ @subspecs_from_libraries = roots.select { |r| Project::DEFAULT_DEPENDENCIES.include?(r) }.map do |root|
295
233
  case root
296
234
  when 'RCTLinking'
297
235
  'RCTLinkingIOS'
@@ -308,18 +246,11 @@ module ReactNativeUtil
308
246
  end
309
247
 
310
248
  def app_target
311
- xcodeproj.targets.find { |t| t.name == app_name }
249
+ project.app_target
312
250
  end
313
251
 
314
252
  def test_target
315
- xcodeproj.targets.select(&:test_target_type?).reject { |t| t.name =~ /tvOS/ }.first
316
- end
317
-
318
- # Validate an assumption about the project. TODO: Provide override option.
319
- # @raise ConversionError if an application target is not found with the same name as the project.
320
- def validate_app_target!
321
- raise ConversionError, "Unable to find target #{app_name} in #{xcodeproj_path}." if app_target.nil?
322
- raise ConversionError, "Target #{app_name} is not an application target." unless app_target.product_type == 'com.apple.product-type.application'
253
+ project.test_target
323
254
  end
324
255
 
325
256
  def podfile_path
@@ -353,55 +284,11 @@ module ReactNativeUtil
353
284
  raise ConversionError, 'Uncommitted changes in repo. Please commit or stash before continuing.'
354
285
  end
355
286
 
356
- # Adds the Start Packager script from the React.xcodeproj under node_modules
357
- # to the main application target before deleting React.xcodeproj from the
358
- # Libraries group. Adjusts paths in the script to account for the different
359
- # project location. If React.xcodeproj cannot be opened, or if the relevant
360
- # build phase is not found, a warning is logged, and this step is skipped.
361
- #
362
- # TODO: The build phase is added after all other build phases. Ideally it
363
- # can be moved to the beginning. The packager is independent of the Xcode
364
- # build process. It may be started at any time. Starting it early is an
365
- # optimization that allows it to load while the build is in progress.
366
- # Currently it's possible to simply drag the build phase in Xcode to a
367
- # higher position after running the react_pod command.
368
- def add_packager_script
369
- old_packager_phase = packager_phase_from_react_project
370
- unless old_packager_phase
371
- log 'Could not find packager build phase in React.xcodeproj. Skipping.'.yellow
372
- return
373
- end
374
-
375
- # location of project is different relative to packager script
376
- script = old_packager_phase.shell_script.gsub(%r{../scripts}, '../node_modules/react-native/scripts')
377
-
378
- phase = app_target.new_shell_script_build_phase old_packager_phase.name
379
- phase.shell_script = script
380
- end
381
-
382
- # Returns a Project object with the contents of the React.xcodeproj project
383
- # from node_modules.
384
- # @return [Xcodeproj::Project] a Project object with the contents of React.xcodeproj from node_modules
287
+ # Load the contents of the React.xcodeproj project from node_modules.
385
288
  # @raise Xcodeproj::PlainInformative in case of most failures
386
- def react_project!
387
- return @react_project if @react_project
388
-
389
- path = libraries_group.children.find { |c| c.path =~ /React.xcodeproj/ }.real_path
390
- @react_project = Xcodeproj::Project.open path
391
- end
392
-
393
- # Returns the original Start Packager build phase from the React.xcodeproj
394
- # under node_modules. This contains the original script.
395
- # @return the packager build phase if found
396
- # @return nil if not found or React.xcodeproj cannot be opened
397
- def packager_phase_from_react_project
398
- react_project!.targets.first.build_phases.find { |p| p.name =~ /packager/i }
399
- rescue Errno::ENOENT
400
- log 'Could not open React.xcodeproj. File not found.'
401
- nil
402
- rescue Xcodeproj::PlainInformative => e
403
- log "Could not open React.xcodeproj. #{e.message}"
404
- nil
289
+ def load_react_project!
290
+ path = project.libraries_group.children.find { |c| c.path =~ /React.xcodeproj/ }.real_path
291
+ @react_project = Project.open path
405
292
  end
406
293
  end
407
294
  end
@@ -1,13 +1,13 @@
1
1
  module ReactNativeUtil
2
2
  # Base class for exceptions from this gem
3
- class ReactNativeUtilException < RuntimeError
3
+ class BaseException < RuntimeError
4
4
  end
5
5
 
6
6
  # Exception raised when command execution fails
7
- class ExecutionError < ReactNativeUtilException
7
+ class ExecutionError < BaseException
8
8
  end
9
9
 
10
10
  # Generic conversion error
11
- class ConversionError < ReactNativeUtilException
11
+ class ConversionError < BaseException
12
12
  end
13
13
  end
@@ -1,7 +1,7 @@
1
1
  # Conversion tools for React Native projects
2
2
  module ReactNativeUtil
3
3
  NAME = 'react_native_util'
4
- VERSION = '0.2.2'
4
+ VERSION = '0.3.0'
5
5
  SUMMARY = 'Community utility CLI for React Native projects'
6
6
  DESCRIPTION = 'Automatically modifies a project created with react-native ' \
7
7
  'init to use the React pod from node_modules.'
@@ -0,0 +1,141 @@
1
+ require 'xcodeproj'
2
+ require_relative 'util'
3
+
4
+ module ReactNativeUtil
5
+ class Project < Xcodeproj::Project
6
+ include Util
7
+
8
+ # [Array<String>] Xcode projects from react-native that may be in the Libraries group
9
+ DEFAULT_DEPENDENCIES = %w[
10
+ ART
11
+ React
12
+ RCTActionSheet
13
+ RCTAnimation
14
+ RCTBlob
15
+ RCTCameraRoll
16
+ RCTGeolocation
17
+ RCTImage
18
+ RCTLinking
19
+ RCTNetwork
20
+ RCTPushNotification
21
+ RCTSettings
22
+ RCTTest
23
+ RCTText
24
+ RCTVibration
25
+ RCTWebSocket
26
+ ]
27
+
28
+ attr_accessor :app_name
29
+
30
+ def app_target
31
+ targets.find { |t| t.name == app_name }
32
+ end
33
+
34
+ def test_target
35
+ targets.select(&:test_target_type?).reject { |t| t.name =~ /tvOS/ }.first
36
+ end
37
+
38
+ # Validate an assumption about the project. TODO: Provide override option.
39
+ # @raise ConversionError if an application target is not found with the same name as the project.
40
+ def validate_app_target!
41
+ raise ConversionError, "Unable to find target #{app_name} in #{path}." if app_target.nil?
42
+ raise ConversionError, "Target #{app_name} is not an application target." unless app_target.product_type == 'com.apple.product-type.application'
43
+ end
44
+
45
+ # A representation of the Libraries group (if any) from the Xcode project.
46
+ # @return the Libraries group
47
+ def libraries_group
48
+ self['Libraries']
49
+ end
50
+
51
+ # Remove the Libraries group from the xcodeproj in memory.
52
+ def remove_libraries_group
53
+ # Remove links against these static libraries
54
+ targets.reject { |t| t.name =~ /-tvOS/ }.each do |t|
55
+ remove_libraries_from_target t
56
+ end
57
+
58
+ log 'Removing Libraries group'
59
+ libraries_group.remove_from_project
60
+ end
61
+
62
+ def remove_libraries_from_target(target)
63
+ log "Removing Libraries from #{target.name}"
64
+ to_remove = target.frameworks_build_phase.files.select do |file|
65
+ path = file.file_ref.pretty_print
66
+ next false unless /^lib(.+)\.a$/.match?(path)
67
+
68
+ static_libs.include?(path)
69
+ end
70
+
71
+ to_remove.each { |f| target.frameworks_build_phase.remove_build_file f }
72
+ end
73
+
74
+ # A list of external dependencies from NPM requiring react-native link.
75
+ # @return [Array<String>] a list of NPM package names
76
+ def dependencies
77
+ return [] if libraries_group.nil?
78
+
79
+ dependency_paths.map do |path|
80
+ # Find the root above the ios/*.xcodeproj under node_modules
81
+ root = File.expand_path '../..', path
82
+ File.basename root
83
+ end
84
+ end
85
+
86
+ # Paths to Xcode projects in the Libraries group from external deps.
87
+ # @return [Array<String>] a list of absolute paths to Xcode projects
88
+ def dependency_paths
89
+ return [] if libraries_group.nil?
90
+
91
+ paths = libraries_group.children.reject { |c| DEFAULT_DEPENDENCIES.include?(c.name.sub(/\.xcodeproj$/, '')) }.map(&:path)
92
+ paths.map { |p| File.expand_path p, File.join(Dir.pwd, 'ios') }
93
+ end
94
+
95
+ def library_roots
96
+ libraries_group.children.map do |library|
97
+ File.basename(library.path).sub(/\.xcodeproj$/, '')
98
+ end
99
+ end
100
+
101
+ # Adds the Start Packager script from the React.xcodeproj under node_modules
102
+ # to the main application target before deleting React.xcodeproj from the
103
+ # Libraries group. Adjusts paths in the script to account for the different
104
+ # project location. If the relevant build phase is not found, a warning is
105
+ # logged, and this step is skipped.
106
+ #
107
+ # TODO: The build phase is added after all other build phases. Ideally it
108
+ # can be moved to the beginning. The packager is independent of the Xcode
109
+ # build process. It may be started at any time. Starting it early is an
110
+ # optimization that allows it to load while the build is in progress.
111
+ # Currently it's possible to simply drag the build phase in Xcode to a
112
+ # higher position after running the react_pod command.
113
+ def add_packager_script_from(react_project)
114
+ old_packager_phase = react_project.packager_phase
115
+ unless old_packager_phase
116
+ log 'Could not find packager build phase in React.xcodeproj. Skipping.'.yellow
117
+ return
118
+ end
119
+
120
+ # location of project is different relative to packager script
121
+ script = old_packager_phase.shell_script.gsub(%r{../scripts}, '../node_modules/react-native/scripts')
122
+
123
+ phase = app_target.new_shell_script_build_phase old_packager_phase.name
124
+ phase.shell_script = script
125
+ end
126
+
127
+ # All static libraries from the Libraries group
128
+ # @return [Array<String>] an array of filenames
129
+ def static_libs
130
+ library_roots.map { |root| "lib#{root}.a" }
131
+ end
132
+
133
+ # Returns the original Start Packager build phase (from the React.xcodeproj
134
+ # under node_modules). This contains the original script.
135
+ # @return the packager build phase if found
136
+ # @return nil if not found
137
+ def packager_phase
138
+ targets.first.build_phases.find { |p| p.name =~ /packager/i }
139
+ end
140
+ end
141
+ end
@@ -1,4 +1,6 @@
1
1
  require 'colored'
2
+ require 'tmpdir'
3
+ require 'tty/platform'
2
4
  require 'tty/spinner'
3
5
  require_relative 'core_ext/io'
4
6
  require_relative 'core_ext/regexp'
@@ -90,5 +92,58 @@ module ReactNativeUtil
90
92
  def log(message)
91
93
  STDOUT.log message
92
94
  end
95
+
96
+ # Determine if a specific command is available.
97
+ #
98
+ # @param command [#to_s] A command to check for
99
+ # @return true if found, false otherwise
100
+ def have_command?(command)
101
+ # May be shell-dependent, OS-dependent
102
+ # Kernel#system does not raise Errno::ENOENT when running under the Bundler
103
+ !`which #{command}`.empty?
104
+ end
105
+
106
+ # Validate one or more commands. If the specified command is not
107
+ # available in the PATH (via which), a ConversionError is raised noting
108
+ # the package to be installed (from Homebrew, e.g.).
109
+ #
110
+ # When package names to be installed differ from command names, a Hash
111
+ # may be used. For example:
112
+ # validate_commands! [:yarn, 'react-native' => 'react-native-cli']
113
+ #
114
+ # @param commands [Array, Hash, #to_s] one or more commands to be validated.
115
+ # @raise ConversionError if any command not found
116
+ def validate_commands!(commands)
117
+ errors = []
118
+
119
+ case commands
120
+ when Array
121
+ # Validate each command in the array, accumulating error messages
122
+ # if necessary.
123
+ commands.each do |c|
124
+ begin
125
+ validate_commands! c
126
+ rescue ConversionError => e
127
+ errors += e.message.split("\n")
128
+ end
129
+ end
130
+ when Hash
131
+ # Each key represents a command to check. The value is the package to
132
+ # install if missing.
133
+ commands.each do |key, value|
134
+ next if have_command?(key)
135
+
136
+ errors << "#{key} command not found. Please install #{value} to continue."
137
+ end
138
+ else
139
+ # commands is a single command to be validated. The package name is the
140
+ # same. Usually a symbol or a string, but only has to respond to #to_s.
141
+ errors << "#{commands} command not found. Please install #{commands} to continue." unless have_command? commands
142
+ end
143
+
144
+ return if errors.empty?
145
+
146
+ raise ConversionError, errors.join("\n")
147
+ end
93
148
  end
94
149
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: react_native_util
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jimmy Dee
@@ -229,6 +229,7 @@ files:
229
229
  - lib/react_native_util/core_ext/string.rb
230
230
  - lib/react_native_util/exceptions.rb
231
231
  - lib/react_native_util/metadata.rb
232
+ - lib/react_native_util/project.rb
232
233
  - lib/react_native_util/rake/react_pod_task.rb
233
234
  - lib/react_native_util/util.rb
234
235
  homepage: https://github.com/jdee/react_native_util