branch_io_cli 0.9.0 → 0.9.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/lib/assets/patches/ContinueUserActivity.m +4 -0
  3. data/lib/assets/patches/ContinueUserActivity.swift +4 -0
  4. data/lib/assets/patches/ContinueUserActivityNew.m +6 -0
  5. data/lib/assets/patches/ContinueUserActivityNew.swift +5 -0
  6. data/lib/assets/patches/DidFinishLaunching.m +4 -0
  7. data/lib/assets/patches/DidFinishLaunching.swift +5 -0
  8. data/lib/assets/patches/DidFinishLaunchingNew.m +9 -0
  9. data/lib/assets/patches/DidFinishLaunchingNew.swift +9 -0
  10. data/lib/assets/patches/DidFinishLaunchingNewTest.m +13 -0
  11. data/lib/assets/patches/DidFinishLaunchingNewTest.swift +13 -0
  12. data/lib/assets/patches/DidFinishLaunchingTest.m +8 -0
  13. data/lib/assets/patches/DidFinishLaunchingTest.swift +9 -0
  14. data/lib/assets/patches/OpenUrl.m +4 -0
  15. data/lib/assets/patches/OpenUrl.swift +4 -0
  16. data/lib/assets/patches/OpenUrlNew.m +6 -0
  17. data/lib/assets/patches/OpenUrlNew.swift +5 -0
  18. data/lib/assets/patches/OpenUrlSourceApplication.m +4 -0
  19. data/lib/assets/patches/OpenUrlSourceApplication.swift +4 -0
  20. data/lib/assets/patches/cartfile.yml +3 -0
  21. data/lib/assets/patches/continue_user_activity_new_objc.yml +2 -0
  22. data/lib/assets/patches/continue_user_activity_new_swift.yml +2 -0
  23. data/lib/assets/patches/continue_user_activity_objc.yml +2 -0
  24. data/lib/assets/patches/continue_user_activity_swift.yml +2 -0
  25. data/lib/assets/patches/did_finish_launching_new_objc.yml +2 -0
  26. data/lib/assets/patches/did_finish_launching_new_swift.yml +2 -0
  27. data/lib/assets/patches/did_finish_launching_new_test_objc.yml +2 -0
  28. data/lib/assets/patches/did_finish_launching_new_test_swift.yml +2 -0
  29. data/lib/assets/patches/did_finish_launching_objc.yml +2 -0
  30. data/lib/assets/patches/did_finish_launching_swift.yml +2 -0
  31. data/lib/assets/patches/did_finish_launching_test_objc.yml +2 -0
  32. data/lib/assets/patches/did_finish_launching_test_swift.yml +2 -0
  33. data/lib/assets/patches/objc_import.yml +3 -0
  34. data/lib/assets/patches/open_url_new_objc.yml +2 -0
  35. data/lib/assets/patches/open_url_new_swift.yml +2 -0
  36. data/lib/assets/patches/open_url_objc.yml +2 -0
  37. data/lib/assets/patches/open_url_source_application_objc.yml +2 -0
  38. data/lib/assets/patches/open_url_source_application_swift.yml +2 -0
  39. data/lib/assets/patches/open_url_swift.yml +2 -0
  40. data/lib/assets/patches/swift_import.yml +3 -0
  41. data/lib/branch_io_cli.rb +2 -1
  42. data/lib/branch_io_cli/cli.rb +3 -3
  43. data/lib/branch_io_cli/command.rb +4 -0
  44. data/lib/branch_io_cli/{commands → command}/command.rb +4 -3
  45. data/lib/branch_io_cli/{commands → command}/report_command.rb +57 -54
  46. data/lib/branch_io_cli/{commands → command}/setup_command.rb +29 -26
  47. data/lib/branch_io_cli/{commands → command}/validate_command.rb +4 -2
  48. data/lib/branch_io_cli/configuration.rb +4 -0
  49. data/lib/branch_io_cli/configuration/configuration.rb +211 -0
  50. data/lib/branch_io_cli/configuration/report_configuration.rb +164 -0
  51. data/lib/branch_io_cli/configuration/setup_configuration.rb +215 -0
  52. data/lib/branch_io_cli/configuration/validate_configuration.rb +26 -0
  53. data/lib/branch_io_cli/core_ext/io.rb +2 -2
  54. data/lib/branch_io_cli/helper.rb +1 -1
  55. data/lib/branch_io_cli/helper/branch_helper.rb +0 -16
  56. data/lib/branch_io_cli/helper/ios_helper.rb +87 -468
  57. data/lib/branch_io_cli/helper/methods.rb +1 -1
  58. data/lib/branch_io_cli/helper/patch_helper.rb +267 -0
  59. data/lib/branch_io_cli/version.rb +1 -1
  60. metadata +55 -11
  61. data/lib/branch_io_cli/commands.rb +0 -4
  62. data/lib/branch_io_cli/helper/configuration_helper.rb +0 -529
@@ -15,7 +15,7 @@ module BranchIOCLI
15
15
  # :command: [String] A shell command to execute
16
16
  # :output: [IO] An optional IO object to receive stdout and stderr from the command
17
17
  def sh(command, output = STDOUT)
18
- status = output.report_command command
18
+ status = output.log_command command
19
19
  raise CommandError, %{Error executing "#{command}": #{status}.} unless status.success?
20
20
  end
21
21
  end
@@ -0,0 +1,267 @@
1
+ require "pattern_patch"
2
+
3
+ module BranchIOCLI
4
+ module Helper
5
+ class PatchHelper
6
+ class << self
7
+ def load_patch(name)
8
+ path = File.expand_path(File.join('..', '..', '..', 'assets', 'patches', "#{name}.yml"), __FILE__)
9
+ PatternPatch::Patch.from_yaml path
10
+ end
11
+
12
+ def config
13
+ Configuration::Configuration.current
14
+ end
15
+
16
+ def helper
17
+ BranchHelper
18
+ end
19
+
20
+ def add_change(change)
21
+ helper.add_change change
22
+ end
23
+
24
+ def patch_bridging_header
25
+ unless config.bridging_header_path
26
+ say "Modules not available and bridging header not found. Cannot import Branch."
27
+ say "Please add use_frameworks! to your Podfile and/or enable modules in your project or use --no-patch-source."
28
+ exit(-1)
29
+ end
30
+
31
+ begin
32
+ bridging_header = File.read config.bridging_header_path
33
+ return false if bridging_header =~ %r{^\s+#import\s+<Branch/Branch.h>|^\s+@import\s+Branch\s*;}
34
+ rescue RuntimeError => e
35
+ say e.message
36
+ say "Cannot read #{config.bridging_header_path}."
37
+ say "Please correct this setting or use --no-patch-source."
38
+ exit(-1)
39
+ end
40
+
41
+ say "Patching #{config.bridging_header_path}"
42
+
43
+ load_patch(:objc_import).apply config.bridging_header_path
44
+ helper.add_change config.bridging_header_path
45
+ end
46
+
47
+ def patch_app_delegate_swift(project)
48
+ return false unless config.swift_version
49
+
50
+ app_delegate_swift = project.files.find { |f| f.path =~ /AppDelegate.swift$/ }
51
+ return false if app_delegate_swift.nil?
52
+
53
+ app_delegate_swift_path = app_delegate_swift.real_path.to_s
54
+
55
+ app_delegate = File.read app_delegate_swift_path
56
+
57
+ # Can't check for the import here, since there may be a bridging header.
58
+ return false if app_delegate =~ /Branch\.initSession/
59
+
60
+ unless config.bridging_header_required?
61
+ load_patch(:swift_import).apply app_delegate_swift_path
62
+ end
63
+
64
+ say "Patching #{app_delegate_swift_path}"
65
+
66
+ patch_did_finish_launching_method_swift app_delegate_swift_path
67
+ patch_continue_user_activity_method_swift app_delegate_swift_path
68
+ patch_open_url_method_swift app_delegate_swift_path
69
+
70
+ add_change app_delegate_swift_path
71
+ true
72
+ end
73
+
74
+ def patch_app_delegate_objc(project)
75
+ app_delegate_objc = project.files.find { |f| f.path =~ /AppDelegate.m$/ }
76
+ return false if app_delegate_objc.nil?
77
+
78
+ app_delegate_objc_path = app_delegate_objc.real_path.to_s
79
+
80
+ app_delegate = File.read app_delegate_objc_path
81
+ return false if app_delegate =~ %r{^\s+#import\s+<Branch/Branch.h>|^\s+@import\s+Branch\s*;}
82
+
83
+ say "Patching #{app_delegate_objc_path}"
84
+
85
+ load_patch(:objc_import).apply app_delegate_objc_path
86
+
87
+ patch_did_finish_launching_method_objc app_delegate_objc_path
88
+ patch_continue_user_activity_method_objc app_delegate_objc_path
89
+ patch_open_url_method_objc app_delegate_objc_path
90
+
91
+ add_change app_delegate_objc_path
92
+ true
93
+ end
94
+
95
+ def patch_did_finish_launching_method_swift(app_delegate_swift_path)
96
+ app_delegate_swift = File.read app_delegate_swift_path
97
+
98
+ patch_name = "did_finish_launching_"
99
+ if app_delegate_swift =~ /didFinishLaunching[^\n]+?\{/m
100
+ # method already present
101
+ patch_name += "test_" unless config.keys.count <= 1 || has_multiple_info_plists?
102
+ patch_name += "swift"
103
+ patch = load_patch patch_name
104
+ patch.regexp = /didFinishLaunchingWithOptions.*?\{[^\n]*\n/m
105
+ else
106
+ # method not present. add entire method
107
+ patch_name += "new_"
108
+ patch_name += "test_" unless config.keys.count <= 1 || has_multiple_info_plists?
109
+ patch_name += "swift"
110
+ patch = load_patch patch_name
111
+ patch.regexp = /var\s+window\s?:\s?UIWindow\?.*?\n/m
112
+ end
113
+ patch.apply app_delegate_swift_path
114
+ end
115
+
116
+ def patch_did_finish_launching_method_objc(app_delegate_objc_path)
117
+ app_delegate_objc = File.read app_delegate_objc_path
118
+
119
+ patch_name = "did_finish_launching_"
120
+ if app_delegate_objc =~ /didFinishLaunchingWithOptions/m
121
+ # method exists. patch it.
122
+ patch_name += "test_" unless config.keys.count <= 1 || has_multiple_info_plists?
123
+ patch_name += "objc"
124
+ patch = load_patch patch_name
125
+ patch.regexp = /didFinishLaunchingWithOptions.*?\{[^\n]*\n/m
126
+ else
127
+ # method does not exist. add it.
128
+ patch_name += "new_"
129
+ patch_name += "test_" unless config.keys.count <= 1 || has_multiple_info_plists?
130
+ patch_name += "objc"
131
+ patch = load_patch patch_name
132
+ patch.regexp = /^@implementation.*?\n/m
133
+ end
134
+ patch.apply app_delegate_objc_path
135
+ end
136
+
137
+ def patch_open_url_method_swift(app_delegate_swift_path)
138
+ app_delegate_swift = File.read app_delegate_swift_path
139
+ patch_name = "open_url_"
140
+ if app_delegate_swift =~ /application.*open\s+url.*options/
141
+ # Has application:openURL:options:
142
+ patch_name += "swift"
143
+ patch = load_patch patch_name
144
+ patch.regexp = /application.*open\s+url.*options:.*?\{.*?\n/m
145
+ elsif app_delegate_swift =~ /application.*open\s+url.*sourceApplication/
146
+ # Has application:openURL:sourceApplication:annotation:
147
+ # TODO: This method is deprecated.
148
+ patch_name += "source_application_swift"
149
+ patch = load_patch patch_name
150
+ patch.regexp = /application.*open\s+url.*sourceApplication:.*?\{.*?\n/m
151
+ else
152
+ # Has neither
153
+ patch_name += "new_swift"
154
+ patch = load_patch patch_name
155
+ patch.regexp = /\n\s*\}[^{}]*\Z/m
156
+ end
157
+ patch.apply app_delegate_swift_path
158
+ end
159
+
160
+ def patch_continue_user_activity_method_swift(app_delegate_swift_path)
161
+ app_delegate = File.read app_delegate_swift_path
162
+ patch_name = "continue_user_activity_"
163
+ if app_delegate =~ /application:.*continue userActivity:.*restorationHandler:/
164
+ # Add something to the top of the method
165
+ patch_name += "swift"
166
+ patch = load_patch patch_name
167
+ patch.regexp = /application:.*continue userActivity:.*restorationHandler:.*?\{.*?\n/m
168
+ else
169
+ # Add the application:continueUserActivity:restorationHandler method if it does not exist
170
+ patch_name += "new_swift"
171
+ patch = load_patch patch_name
172
+ patch.regexp = /\n\s*\}[^{}]*\Z/m
173
+ end
174
+ patch.apply app_delegate_swift_path
175
+ end
176
+
177
+ def patch_open_url_method_objc(app_delegate_objc_path)
178
+ app_delegate_objc = File.read app_delegate_objc_path
179
+ patch_name = "open_url_"
180
+ if app_delegate_objc =~ /application:.*openURL:.*options/
181
+ # Has application:openURL:options:
182
+ patch_name += "objc"
183
+ patch = load_patch patch_name
184
+ patch.regexp = /application:.*openURL:.*options:.*?\{.*?\n/m
185
+ elsif app_delegate_objc =~ /application:.*openURL:.*sourceApplication/
186
+ # Has application:openURL:sourceApplication:annotation:
187
+ patch_name += "source_application_objc"
188
+ patch = load_patch patch_name
189
+ patch.regexp = /application:.*openURL:.*sourceApplication:.*?\{.*?\n/m
190
+ else
191
+ # Has neither
192
+ patch_name += "new_objc"
193
+ patch = load_patch patch_name
194
+ patch.regexp = /\n\s*@end[^@]*\Z/m
195
+ end
196
+ patch.apply app_delegate_objc_path
197
+ end
198
+
199
+ def patch_continue_user_activity_method_objc(app_delegate_objc_path)
200
+ app_delegate = File.read app_delegate_objc_path
201
+ patch_name = "continue_user_activity_"
202
+ if app_delegate =~ /application:.*continueUserActivity:.*restorationHandler:/
203
+ patch_name += "objc"
204
+ patch = load_patch patch_name
205
+ patch.regexp = /application:.*continueUserActivity:.*restorationHandler:.*?\{.*?\n/m
206
+ else
207
+ # Add the application:continueUserActivity:restorationHandler method if it does not exist
208
+ patch_name += "new_objc"
209
+ patch = load_patch patch_name
210
+ patch.regexp = /\n\s*@end[^@]*\Z/m
211
+ end
212
+ patch.apply app_delegate_objc_path
213
+ end
214
+
215
+ def patch_podfile(podfile_path)
216
+ podfile = File.read podfile_path
217
+
218
+ # Podfile already contains the Branch pod
219
+ # TODO: Allow for adding to multiple targets in the Podfile
220
+ return false if podfile =~ /pod\s+('Branch'|"Branch")/
221
+
222
+ say "Adding pod \"Branch\" to #{podfile_path}"
223
+
224
+ if podfile =~ /target\s+(["'])#{config.target.name}\1\s+do.*?\n/m
225
+ # if there is a target block for this target:
226
+ patch = PatternPatch::Patch.new(
227
+ regexp: /\n(\s*)target\s+(["'])#{config.target.name}\2\s+do.*?\n/m,
228
+ text: "\\1 pod \"Branch\"\n",
229
+ mode: :append
230
+ )
231
+ else
232
+ # add to the abstract_target for this target
233
+ patch = PatternPatch::Patch.new(
234
+ regexp: /^(\s*)target\s+["']#{config.target.name}/,
235
+ text: "\\1pod \"Branch\"\n",
236
+ mode: :prepend
237
+ )
238
+ end
239
+ patch.apply podfile_path
240
+
241
+ true
242
+ end
243
+
244
+ def patch_cartfile(cartfile_path)
245
+ cartfile = File.read cartfile_path
246
+
247
+ # Cartfile already contains the Branch framework
248
+ return false if cartfile =~ /git.+Branch/
249
+
250
+ say "Adding \"Branch\" to #{cartfile_path}"
251
+
252
+ load_patch(:cartfile).apply cartfile_path
253
+
254
+ true
255
+ end
256
+
257
+ def patch_source(xcodeproj)
258
+ # Patch the bridging header any time Swift imports are not available,
259
+ # to make Branch available throughout the app, whether the AppDelegate
260
+ # is in Swift or Objective-C.
261
+ patch_bridging_header if config.bridging_header_required?
262
+ patch_app_delegate_swift(xcodeproj) || patch_app_delegate_objc(xcodeproj)
263
+ end
264
+ end
265
+ end
266
+ end
267
+ end
@@ -1,3 +1,3 @@
1
1
  module BranchIOCLI
2
- VERSION = "0.9.0"
2
+ VERSION = "0.9.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: branch_io_cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.9.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Branch
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-11-03 00:00:00.000000000 Z
12
+ date: 2017-11-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: CFPropertyList
@@ -59,14 +59,14 @@ dependencies:
59
59
  requirements:
60
60
  - - ">="
61
61
  - !ruby/object:Gem::Version
62
- version: '0'
62
+ version: 0.3.0
63
63
  type: :runtime
64
64
  prerelease: false
65
65
  version_requirements: !ruby/object:Gem::Requirement
66
66
  requirements:
67
67
  - - ">="
68
68
  - !ruby/object:Gem::Version
69
- version: '0'
69
+ version: 0.3.0
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: plist
72
72
  requirement: !ruby/object:Gem::Requirement
@@ -250,21 +250,65 @@ files:
250
250
  - bin/branch_io
251
251
  - lib/assets/completions/completion.bash
252
252
  - lib/assets/completions/completion.zsh
253
+ - lib/assets/patches/ContinueUserActivity.m
254
+ - lib/assets/patches/ContinueUserActivity.swift
255
+ - lib/assets/patches/ContinueUserActivityNew.m
256
+ - lib/assets/patches/ContinueUserActivityNew.swift
257
+ - lib/assets/patches/DidFinishLaunching.m
258
+ - lib/assets/patches/DidFinishLaunching.swift
259
+ - lib/assets/patches/DidFinishLaunchingNew.m
260
+ - lib/assets/patches/DidFinishLaunchingNew.swift
261
+ - lib/assets/patches/DidFinishLaunchingNewTest.m
262
+ - lib/assets/patches/DidFinishLaunchingNewTest.swift
263
+ - lib/assets/patches/DidFinishLaunchingTest.m
264
+ - lib/assets/patches/DidFinishLaunchingTest.swift
265
+ - lib/assets/patches/OpenUrl.m
266
+ - lib/assets/patches/OpenUrl.swift
267
+ - lib/assets/patches/OpenUrlNew.m
268
+ - lib/assets/patches/OpenUrlNew.swift
269
+ - lib/assets/patches/OpenUrlSourceApplication.m
270
+ - lib/assets/patches/OpenUrlSourceApplication.swift
271
+ - lib/assets/patches/cartfile.yml
272
+ - lib/assets/patches/continue_user_activity_new_objc.yml
273
+ - lib/assets/patches/continue_user_activity_new_swift.yml
274
+ - lib/assets/patches/continue_user_activity_objc.yml
275
+ - lib/assets/patches/continue_user_activity_swift.yml
276
+ - lib/assets/patches/did_finish_launching_new_objc.yml
277
+ - lib/assets/patches/did_finish_launching_new_swift.yml
278
+ - lib/assets/patches/did_finish_launching_new_test_objc.yml
279
+ - lib/assets/patches/did_finish_launching_new_test_swift.yml
280
+ - lib/assets/patches/did_finish_launching_objc.yml
281
+ - lib/assets/patches/did_finish_launching_swift.yml
282
+ - lib/assets/patches/did_finish_launching_test_objc.yml
283
+ - lib/assets/patches/did_finish_launching_test_swift.yml
284
+ - lib/assets/patches/objc_import.yml
285
+ - lib/assets/patches/open_url_new_objc.yml
286
+ - lib/assets/patches/open_url_new_swift.yml
287
+ - lib/assets/patches/open_url_objc.yml
288
+ - lib/assets/patches/open_url_source_application_objc.yml
289
+ - lib/assets/patches/open_url_source_application_swift.yml
290
+ - lib/assets/patches/open_url_swift.yml
291
+ - lib/assets/patches/swift_import.yml
253
292
  - lib/branch_io_cli.rb
254
293
  - lib/branch_io_cli/cli.rb
255
- - lib/branch_io_cli/commands.rb
256
- - lib/branch_io_cli/commands/command.rb
257
- - lib/branch_io_cli/commands/report_command.rb
258
- - lib/branch_io_cli/commands/setup_command.rb
259
- - lib/branch_io_cli/commands/validate_command.rb
294
+ - lib/branch_io_cli/command.rb
295
+ - lib/branch_io_cli/command/command.rb
296
+ - lib/branch_io_cli/command/report_command.rb
297
+ - lib/branch_io_cli/command/setup_command.rb
298
+ - lib/branch_io_cli/command/validate_command.rb
299
+ - lib/branch_io_cli/configuration.rb
300
+ - lib/branch_io_cli/configuration/configuration.rb
301
+ - lib/branch_io_cli/configuration/report_configuration.rb
302
+ - lib/branch_io_cli/configuration/setup_configuration.rb
303
+ - lib/branch_io_cli/configuration/validate_configuration.rb
260
304
  - lib/branch_io_cli/core_ext.rb
261
305
  - lib/branch_io_cli/core_ext/io.rb
262
306
  - lib/branch_io_cli/helper.rb
263
307
  - lib/branch_io_cli/helper/android_helper.rb
264
308
  - lib/branch_io_cli/helper/branch_helper.rb
265
- - lib/branch_io_cli/helper/configuration_helper.rb
266
309
  - lib/branch_io_cli/helper/ios_helper.rb
267
310
  - lib/branch_io_cli/helper/methods.rb
311
+ - lib/branch_io_cli/helper/patch_helper.rb
268
312
  - lib/branch_io_cli/version.rb
269
313
  homepage: http://github.com/BranchMetrics/branch_io_cli
270
314
  licenses:
@@ -286,7 +330,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
286
330
  version: '0'
287
331
  requirements: []
288
332
  rubyforge_project:
289
- rubygems_version: 2.7.0
333
+ rubygems_version: 2.7.1
290
334
  signing_key:
291
335
  specification_version: 4
292
336
  summary: Branch.io command-line interface for mobile app integration
@@ -1,4 +0,0 @@
1
- require "branch_io_cli/commands/command"
2
- require "branch_io_cli/commands/report_command"
3
- require "branch_io_cli/commands/setup_command"
4
- require "branch_io_cli/commands/validate_command"
@@ -1,529 +0,0 @@
1
- require "pathname"
2
- require "xcodeproj"
3
-
4
- module BranchIOCLI
5
- module Helper
6
- # Processes CLI options.
7
- # Validates options.
8
- # Prompts for input in a number of cases.
9
- # rubocop: disable Metrics/ClassLength
10
- class ConfigurationHelper
11
- APP_LINK_REGEXP = /\.app\.link$|\.test-app\.link$/
12
- SDK_OPTIONS =
13
- {
14
- "Set this project up to use CocoaPods and add the Branch SDK." => :cocoapods,
15
- "Set this project up to use Carthage and add the Branch SDK." => :carthage,
16
- "Add Branch.framework directly to the project's dependencies." => :direct,
17
- "Skip adding the framework to the project." => :skip
18
- }
19
-
20
- class << self
21
- attr_reader :xcodeproj_path
22
- attr_reader :xcodeproj
23
- attr_reader :workspace_path
24
- attr_reader :workspace
25
- attr_reader :keys
26
- attr_reader :all_domains
27
- attr_reader :podfile_path
28
- attr_reader :cartfile_path
29
- attr_reader :carthage_command
30
- attr_reader :target
31
- attr_reader :uri_scheme
32
- attr_reader :pod_repo_update
33
- attr_reader :validate
34
- attr_reader :add_sdk
35
- attr_reader :force
36
- attr_reader :patch_source
37
- attr_reader :commit
38
- attr_reader :sdk_integration_mode
39
- attr_reader :clean
40
- attr_reader :header_only
41
- attr_reader :scheme
42
- attr_reader :configuration
43
- attr_reader :report_path
44
- attr_reader :sdk
45
-
46
- def validate_setup_options(options)
47
- print_identification "setup"
48
-
49
- @pod_repo_update = options.pod_repo_update
50
- @validate = options.validate
51
- @patch_source = options.patch_source
52
- @add_sdk = options.add_sdk
53
- @force = options.force
54
- @commit = options.commit
55
-
56
- say "--force is ignored when --no-validate is used." if !options.validate && options.force
57
- if options.cartfile && options.podfile
58
- say "--cartfile and --podfile are mutually exclusive. Please specify the file to patch."
59
- exit 1
60
- end
61
-
62
- validate_xcodeproj_path options
63
- validate_target options
64
- validate_keys_from_setup_options options
65
- validate_all_domains options, !@target.extension_target_type?
66
- validate_uri_scheme options
67
-
68
- # If neither --podfile nor --cartfile is present, arbitrarily look for a Podfile
69
- # first.
70
-
71
- # If --cartfile is present, don't look for a Podfile. Just validate that
72
- # Cartfile.
73
- validate_buildfile_path options.podfile, "Podfile" if options.cartfile.nil? && options.add_sdk
74
-
75
- # If --podfile is present or a Podfile was found, don't look for a Cartfile.
76
- validate_buildfile_path options.cartfile, "Cartfile" if @sdk_integration_mode.nil? && options.add_sdk
77
- @carthage_command = options.carthage_command if @sdk_integration_mode == :carthage
78
-
79
- validate_sdk_addition options
80
-
81
- BranchHelper.verify_git if @commit
82
-
83
- print_setup_configuration
84
- end
85
-
86
- def validate_validation_options(options)
87
- print_identification "validate"
88
-
89
- validate_xcodeproj_path options
90
- validate_target options, false
91
-
92
- print_validation_configuration
93
- end
94
-
95
- def validate_report_options(options)
96
- print_identification "report"
97
-
98
- @clean = options.clean
99
- @header_only = options.header_only
100
- @scheme = options.scheme
101
- @target = options.target
102
- @configuration = options.configuration
103
- @report_path = options.out
104
- @sdk = options.sdk
105
- @pod_repo_update = options.pod_repo_update
106
-
107
- validate_xcodeproj_and_workspace options
108
- validate_target options
109
- validate_scheme options
110
-
111
- # If neither --podfile nor --cartfile is present, arbitrarily look for a Podfile
112
- # first.
113
-
114
- # If --cartfile is present, don't look for a Podfile. Just validate that
115
- # Cartfile.
116
- validate_buildfile_path(options.podfile, "Podfile") if options.cartfile.nil?
117
-
118
- # If --podfile is present or a Podfile was found, don't look for a Cartfile.
119
- validate_buildfile_path(options.cartfile, "Cartfile") if @sdk_integration_mode.nil?
120
-
121
- print_report_configuration
122
- end
123
-
124
- def print_identification(command)
125
- say <<EOF
126
-
127
- <%= color("branch_io #{command} v. #{VERSION}", BOLD) %>
128
-
129
- EOF
130
- end
131
-
132
- def print_setup_configuration
133
- say <<EOF
134
- <%= color('Configuration:', [CYAN, BOLD, UNDERLINE]) %>
135
-
136
- <%= color('Xcode project:', BOLD) %> #{@xcodeproj_path}
137
- <%= color('Target:', BOLD) %> #{@target.name}
138
- <%= color('Live key:', BOLD) %> #{@keys[:live] || '(none)'}
139
- <%= color('Test key:', BOLD) %> #{@keys[:test] || '(none)'}
140
- <%= color('Domains:', BOLD) %> #{@all_domains}
141
- <%= color('URI scheme:', BOLD) %> #{@uri_scheme || '(none)'}
142
- <%= color('Podfile:', BOLD) %> #{@podfile_path || '(none)'}
143
- <%= color('Cartfile:', BOLD) %> #{@cartfile_path || '(none)'}
144
- <%= color('Carthage command:', BOLD) %> #{@carthage_command || '(none)'}
145
- <%= color('Pod repo update:', BOLD) %> #{@pod_repo_update.inspect}
146
- <%= color('Validate:', BOLD) %> #{@validate.inspect}
147
- <%= color('Force:', BOLD) %> #{@force.inspect}
148
- <%= color('Add SDK:', BOLD) %> #{@add_sdk.inspect}
149
- <%= color('Patch source:', BOLD) %> #{@patch_source.inspect}
150
- <%= color('Commit:', BOLD) %> #{@commit.inspect}
151
- <%= color('SDK integration mode:', BOLD) %> #{@sdk_integration_mode || '(none)'}
152
-
153
- EOF
154
- end
155
-
156
- def print_validation_configuration
157
- say <<EOF
158
- <%= color('Configuration:', [CYAN, BOLD, UNDERLINE]) %>
159
-
160
- <%= color('Xcode project:', BOLD) %> #{@xcodeproj_path}
161
- <%= color('Target:', BOLD) %> #{@target.name}
162
- <%= color('Domains:', BOLD) %> #{@all_domains || '(none)'}
163
- EOF
164
- end
165
-
166
- def print_report_configuration
167
- say <<EOF
168
- <%= color('Configuration:', [CYAN, BOLD, UNDERLINE]) %>
169
-
170
- <%= color('Xcode workspace:', BOLD) %> #{@workspace_path || '(none)'}
171
- <%= color('Xcode project:', BOLD) %> #{@xcodeproj_path || '(none)'}
172
- <%= color('Scheme:', BOLD) %> #{@scheme || '(none)'}
173
- <%= color('Target:', BOLD) %> #{@target || '(none)'}
174
- <%= color('Configuration:', BOLD) %> #{@configuration}
175
- <%= color('SDK:', BOLD) %> #{@sdk}
176
- <%= color('Podfile:', BOLD) %> #{@podfile_path || '(none)'}
177
- <%= color('Cartfile:', BOLD) %> #{@cartfile_path || '(none)'}
178
- <%= color('Pod repo update:', BOLD) %> #{@pod_repo_update.inspect}
179
- <%= color('Clean:', BOLD) %> #{@clean.inspect}
180
- <%= color('Report path:', BOLD) %> #{@report_path}
181
- EOF
182
- end
183
-
184
- def validate_keys_from_setup_options(options)
185
- live_key = options.live_key
186
- test_key = options.test_key
187
- @keys = {}
188
- @keys[:live] = live_key unless live_key.nil?
189
- @keys[:test] = test_key unless test_key.nil?
190
-
191
- while @keys.empty?
192
- say "A live key, a test key or both is required."
193
- live_key = ask "Please enter your live Branch key or use --live_key [enter for none]: "
194
- test_key = ask "Please enter your test Branch key or use --test_key [enter for none]: "
195
-
196
- @keys[:live] = live_key unless live_key == ""
197
- @keys[:test] = test_key unless test_key == ""
198
- end
199
- end
200
-
201
- def validate_all_domains(options, required = true)
202
- app_link_roots = app_link_roots_from_domains options.domains
203
-
204
- unless options.app_link_subdomain.nil? || app_link_roots.include?(options.app_link_subdomain)
205
- app_link_roots << options.app_link_subdomain
206
- end
207
-
208
- # app_link_roots now contains options.app_link_subdomain, if supplied, and the roots of any
209
- # .app.link or .test-app.link domains provided via options.domains.
210
-
211
- app_link_subdomains = app_link_subdomains_from_roots app_link_roots
212
-
213
- custom_domains = custom_domains_from_domains options.domains
214
-
215
- @all_domains = (app_link_subdomains + custom_domains).uniq
216
-
217
- while required && @all_domains.empty?
218
- domains = ask "Please enter domains as a comma-separated list: ", ->(str) { str.split "," }
219
-
220
- @all_domains = all_domains_from_domains domains
221
- end
222
- end
223
-
224
- def validate_uri_scheme(options)
225
- # No validation at the moment. Just strips off any trailing ://
226
- @uri_scheme = uri_scheme_without_suffix options.uri_scheme
227
- end
228
-
229
- # 1. Look for options.xcodeproj.
230
- # 2. If not specified, look for projects under . (excluding anything in Pods or Carthage folder).
231
- # 3. If none or more than one found, prompt the user.
232
- def validate_xcodeproj_path(options)
233
- if options.xcodeproj
234
- path = options.xcodeproj
235
- else
236
- all_xcodeproj_paths = Dir[File.expand_path(File.join(".", "**/*.xcodeproj"))]
237
- # find an xcodeproj (ignoring the Pods and Carthage folders)
238
- # TODO: Improve this filter
239
- xcodeproj_paths = all_xcodeproj_paths.select do |p|
240
- valid = true
241
- Pathname.new(p).each_filename do |f|
242
- valid = false && break if f == "Carthage" || f == "Pods"
243
- end
244
- valid
245
- end
246
-
247
- path = xcodeproj_paths.first if xcodeproj_paths.count == 1
248
- end
249
-
250
- loop do
251
- path = ask "Please enter the path to your Xcode project or use --xcodeproj: " if path.nil?
252
- # TODO: Allow the user to choose if xcodeproj_paths.count > 0
253
- begin
254
- @xcodeproj = Xcodeproj::Project.open path
255
- @xcodeproj_path = path
256
- return
257
- rescue StandardError => e
258
- say e.message
259
- path = nil
260
- end
261
- end
262
- end
263
-
264
- # rubocop: disable Metrics/PerceivedComplexity
265
- def validate_xcodeproj_and_workspace(options)
266
- # 1. What was passed in?
267
- begin
268
- if options.workspace
269
- path = options.workspace
270
- @workspace = Xcodeproj::Workspace.new_from_xcworkspace options.workspace
271
- @workspace_path = options.workspace
272
- end
273
- if options.xcodeproj
274
- path = options.xcodeproj
275
- @xcodeproj = Xcodeproj::Project.open options.xcodeproj
276
- @xcodeproj_path = options.xcodeproj
277
- else
278
- # Pass --workspace and --xcodeproj to override this inference.
279
- if @workspace && @workspace.file_references.count > 0 && @workspace.file_references.first.path =~ /\.xcodeproj$/
280
- @xcodeproj_path = File.expand_path "../#{@workspace.file_references.first.path}", @workspace_path
281
- @xcodeproj = Xcodeproj::Project.open @xcodeproj_path
282
- end
283
- end
284
- return if @workspace || @xcodeproj
285
- rescue StandardError => e
286
- say e.message
287
- end
288
-
289
- # Try to find first a workspace, then a project
290
- all_workspace_paths = Dir[File.expand_path(File.join(".", "**/*.xcworkspace"))]
291
- .reject { |w| w =~ %r{/project.xcworkspace$} }
292
- .select do |p|
293
- valid = true
294
- Pathname.new(p).each_filename do |f|
295
- valid = false && break if f == "Carthage" || f == "Pods"
296
- end
297
- valid
298
- end
299
-
300
- if all_workspace_paths.count == 1
301
- path = all_workspace_paths.first
302
- elsif all_workspace_paths.count == 0
303
- all_xcodeproj_paths = Dir[File.expand_path(File.join(".", "**/*.xcodeproj"))]
304
- xcodeproj_paths = all_xcodeproj_paths.select do |p|
305
- valid = true
306
- Pathname.new(p).each_filename do |f|
307
- valid = false && break if f == "Carthage" || f == "Pods"
308
- end
309
- valid
310
- end
311
-
312
- path = xcodeproj_paths.first if xcodeproj_paths.count == 1
313
- end
314
- # If more than one workspace. Don't try to find a project. Just prompt.
315
-
316
- loop do
317
- path = ask "Please enter a path to your Xcode project or workspace: " if path.nil?
318
- begin
319
- if path =~ /\.xcworkspace$/
320
- @workspace = Xcodeproj::Workspace.new_from_xcworkspace path
321
- @workspace_path = path
322
-
323
- # Pass --workspace and --xcodeproj to override this inference.
324
- if @workspace.file_references.count > 0 && @workspace.file_references.first.path =~ /\.xcodeproj$/
325
- @xcodeproj_path = File.expand_path "../#{@workspace.file_references.first.path}", @workspace_path
326
- @xcodeproj = Xcodeproj::Project.open @xcodeproj_path
327
- end
328
-
329
- return
330
- elsif path =~ /\.xcodeproj$/
331
- @xcodeproj = Xcodeproj::Project.open path
332
- @xcodeproj_path = path
333
- return
334
- else
335
- say "Path must end with .xcworkspace or .xcodeproj"
336
- end
337
- rescue StandardError => e
338
- say e.message
339
- end
340
- end
341
- end
342
- # rubocop: enable Metrics/PerceivedComplexity
343
-
344
- def validate_scheme(options)
345
- schemes = all_schemes
346
- # TODO: Prompt if --scheme specified but not found.
347
- if options.scheme && schemes.include?(options.scheme)
348
- @scheme = options.scheme
349
- elsif schemes.count == 1
350
- @scheme = schemes.first
351
- elsif !schemes.empty?
352
- # By default, take a scheme with the same name as the target name.
353
- return if (@scheme = schemes.find { |s| s == @target.name })
354
-
355
- say "Please specify one of the following for the --scheme argument:"
356
- schemes.each do |scheme|
357
- say " #{scheme}"
358
- end
359
- exit 1
360
- else
361
- say "No scheme defined in project."
362
- exit(-1)
363
- end
364
- end
365
-
366
- def all_schemes
367
- if @workspace_path
368
- @workspace.schemes.keys.reject { |scheme| scheme == "Pods" }
369
- else
370
- Xcodeproj::Project.schemes @xcodeproj_path
371
- end
372
- end
373
-
374
- def validate_target(options, allow_extensions = true)
375
- non_test_targets = @xcodeproj.targets.reject(&:test_target_type?)
376
- raise "No non-test target found in project" if non_test_targets.empty?
377
-
378
- valid_targets = non_test_targets.reject { |t| !allow_extensions && t.extension_target_type? }
379
-
380
- begin
381
- target = BranchHelper.target_from_project @xcodeproj, options.target
382
-
383
- # If a test target was explicitly specified.
384
- raise "Cannot use test targets" if target.test_target_type?
385
-
386
- # If an extension target was explicitly specified for validation.
387
- raise "Extension targets not allowed for this command" if !allow_extensions && target.extension_target_type?
388
-
389
- @target = target
390
- rescue StandardError => e
391
- say e.message
392
-
393
- choice = choose do |menu|
394
- valid_targets.each { |t| menu.choice t.name }
395
- menu.prompt = "Which target do you wish to use? "
396
- end
397
-
398
- @target = @xcodeproj.targets.find { |t| t.name = choice }
399
- end
400
- end
401
-
402
- def app_link_roots_from_domains(domains)
403
- return [] if domains.nil?
404
-
405
- domains.select { |d| d =~ APP_LINK_REGEXP }
406
- .map { |d| d.sub(APP_LINK_REGEXP, '').sub(/-alternate$/, '') }
407
- .uniq
408
- end
409
-
410
- def custom_domains_from_domains(domains)
411
- return [] if domains.nil?
412
- domains.reject { |d| d =~ APP_LINK_REGEXP }.uniq
413
- end
414
-
415
- def app_link_subdomains(root)
416
- app_link_subdomain = root
417
- return [] if app_link_subdomain.nil?
418
-
419
- live_key = @keys[:live]
420
- test_key = @keys[:test]
421
-
422
- domains = []
423
- unless live_key.nil?
424
- domains += [
425
- "#{app_link_subdomain}.app.link",
426
- "#{app_link_subdomain}-alternate.app.link"
427
- ]
428
- end
429
- unless test_key.nil?
430
- domains += [
431
- "#{app_link_subdomain}.test-app.link",
432
- "#{app_link_subdomain}-alternate.test-app.link"
433
- ]
434
- end
435
- domains
436
- end
437
-
438
- def app_link_subdomains_from_roots(roots)
439
- roots.inject([]) { |domains, root| domains + app_link_subdomains(root) }
440
- end
441
-
442
- def all_domains_from_domains(domains)
443
- app_link_roots = app_link_roots_from_domains domains
444
- app_link_subdomains = app_link_subdomains_from_roots app_link_roots
445
- custom_domains = custom_domains_from_domains domains
446
- custom_domains + app_link_subdomains
447
- end
448
-
449
- # Removes any trailing :// from the argument and returns a copy
450
- def uri_scheme_without_suffix(scheme)
451
- return nil if scheme.nil?
452
- scheme.sub %r{://$}, ""
453
- end
454
-
455
- def validate_buildfile_path(buildfile_path, filename)
456
- # Disable Podfile/Cartfile update if --no-add-sdk is present
457
- return unless @sdk_integration_mode.nil?
458
-
459
- # Was --podfile/--cartfile used?
460
- if buildfile_path
461
- # Yes: Validate. Prompt if not valid.
462
- loop do
463
- valid = buildfile_path =~ %r{/?#{filename}$}
464
- say "#{filename} path must end in /#{filename}." unless valid
465
-
466
- if valid
467
- valid = File.exist? buildfile_path
468
- say "#{buildfile_path} not found." unless valid
469
- end
470
-
471
- if valid
472
- if filename == "Podfile"
473
- @podfile_path = buildfile_path
474
- else
475
- @cartfile_path = buildfile_path
476
- end
477
- return
478
- end
479
-
480
- buildfile_path = ask "Please enter the path to your #{filename}: "
481
- end
482
- end
483
-
484
- # No: Check for Podfile/Cartfile next to workspace or project
485
- buildfile_path = File.expand_path "../#{filename}", (@workspace_path || @xcodeproj_path)
486
- return unless File.exist? buildfile_path
487
-
488
- # Exists: Use it (valid if found)
489
- if filename == "Podfile"
490
- @podfile_path = buildfile_path
491
- else
492
- @cartfile_path = buildfile_path
493
- end
494
-
495
- @sdk_integration_mode = filename == "Podfile" ? :cocoapods : :carthage
496
- end
497
-
498
- def validate_sdk_addition(options)
499
- return if !options.add_sdk || @sdk_integration_mode
500
-
501
- # If no CocoaPods or Carthage, check to see if the framework is linked.
502
- target = BranchHelper.target_from_project @xcodeproj, options.target
503
- return if target.frameworks_build_phase.files.map(&:file_ref).map(&:path).any? { |p| p =~ /Branch.framework$/ }
504
-
505
- # --podfile, --cartfile not specified. No Podfile found. No Cartfile found. No Branch.framework in project.
506
- # Prompt the user:
507
- selected = choose do |menu|
508
- menu.header = "No Podfile or Cartfile specified or found. Here are your options"
509
-
510
- SDK_OPTIONS.each_key { |k| menu.choice k }
511
-
512
- menu.prompt = "What would you like to do?"
513
- end
514
-
515
- @sdk_integration_mode = SDK_OPTIONS[selected]
516
-
517
- case @sdk_integration_mode
518
- when :cocoapods
519
- @podfile_path = File.expand_path "../Podfile", @xcodeproj_path
520
- when :carthage
521
- @cartfile_path = File.expand_path "../Cartfile", @xcodeproj_path
522
- @carthage_command = options.carthage_command
523
- end
524
- end
525
- end
526
- end
527
- # rubocop: enable Metrics/ClassLength
528
- end
529
- end