react_native_util 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +39 -31
- data/lib/assets/templates/Podfile.erb +3 -0
- data/lib/react_native_util/converter.rb +47 -160
- data/lib/react_native_util/exceptions.rb +3 -3
- data/lib/react_native_util/metadata.rb +1 -1
- data/lib/react_native_util/project.rb +141 -0
- data/lib/react_native_util/util.rb +55 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7f874dfbe6f26ca09e59e9392f1e6591d09148b6a34aba766a41feea3bb2957e
|
|
4
|
+
data.tar.gz: 6ccfddce4c25414ef398924bb426dc0191851fb40c1ad6477e19f1eb3970b6cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
18
|
-
|
|
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-
|
|
60
|
-
[✔] yarn install success in
|
|
61
|
-
2019-05-
|
|
62
|
-
2019-05-
|
|
63
|
-
2019-05-
|
|
64
|
-
2019-05-
|
|
65
|
-
2019-05-
|
|
66
|
-
2019-05-
|
|
67
|
-
2019-05-
|
|
68
|
-
2019-05-
|
|
69
|
-
2019-05-
|
|
70
|
-
2019-05-
|
|
71
|
-
2019-05-
|
|
72
|
-
2019-05-
|
|
73
|
-
2019-05-
|
|
74
|
-
2019-05-
|
|
75
|
-
2019-05-
|
|
76
|
-
2019-05-
|
|
77
|
-
[✔] react-native unlink react-native-webview success in 0.
|
|
78
|
-
2019-05-
|
|
79
|
-
2019-05-
|
|
80
|
-
2019-05-
|
|
81
|
-
2019-05-
|
|
82
|
-
2019-05-
|
|
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-
|
|
85
|
-
[✔] pod install success in
|
|
86
|
-
2019-05-
|
|
87
|
-
2019-05-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
# [
|
|
45
|
-
attr_reader :
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
116
|
+
project.remove_libraries_group
|
|
117
117
|
|
|
118
|
-
|
|
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
|
-
@
|
|
211
|
-
@
|
|
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
|
-
|
|
249
|
+
project.app_target
|
|
312
250
|
end
|
|
313
251
|
|
|
314
252
|
def test_target
|
|
315
|
-
|
|
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
|
-
#
|
|
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
|
|
387
|
-
|
|
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
|
|
3
|
+
class BaseException < RuntimeError
|
|
4
4
|
end
|
|
5
5
|
|
|
6
6
|
# Exception raised when command execution fails
|
|
7
|
-
class ExecutionError <
|
|
7
|
+
class ExecutionError < BaseException
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
# Generic conversion error
|
|
11
|
-
class ConversionError <
|
|
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.
|
|
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.
|
|
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
|