branch_io_cli 0.9.0 → 0.9.1

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.
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
@@ -0,0 +1,215 @@
1
+ module BranchIOCLI
2
+ module Configuration
3
+ class SetupConfiguration < Configuration
4
+ APP_LINK_REGEXP = /\.app\.link$|\.test-app\.link$/
5
+ SDK_OPTIONS =
6
+ {
7
+ "Set this project up to use CocoaPods and add the Branch SDK." => :cocoapods,
8
+ "Set this project up to use Carthage and add the Branch SDK." => :carthage,
9
+ "Add Branch.framework directly to the project's dependencies." => :direct,
10
+ "Skip adding the framework to the project." => :skip
11
+ }
12
+
13
+ attr_reader :keys
14
+ attr_reader :all_domains
15
+ attr_reader :carthage_command
16
+ attr_reader :uri_scheme
17
+ attr_reader :validate
18
+ attr_reader :add_sdk
19
+ attr_reader :force
20
+ attr_reader :patch_source
21
+ attr_reader :commit
22
+
23
+ def validate_options
24
+ @validate = options.validate
25
+ @patch_source = options.patch_source
26
+ @add_sdk = options.add_sdk
27
+ @force = options.force
28
+ @commit = options.commit
29
+
30
+ say "--force is ignored when --no-validate is used." if !options.validate && options.force
31
+ if options.cartfile && options.podfile
32
+ say "--cartfile and --podfile are mutually exclusive. Please specify the file to patch."
33
+ exit 1
34
+ end
35
+
36
+ validate_xcodeproj_path
37
+ validate_target
38
+ validate_keys_from_setup_options options
39
+ validate_all_domains options, !target.extension_target_type?
40
+ validate_uri_scheme options
41
+
42
+ # If neither --podfile nor --cartfile is present, arbitrarily look for a Podfile
43
+ # first.
44
+
45
+ # If --cartfile is present, don't look for a Podfile. Just validate that
46
+ # Cartfile.
47
+ validate_buildfile_path options.podfile, "Podfile" if options.cartfile.nil? && options.add_sdk
48
+
49
+ # If --podfile is present or a Podfile was found, don't look for a Cartfile.
50
+ validate_buildfile_path options.cartfile, "Cartfile" if sdk_integration_mode.nil? && options.add_sdk
51
+ @carthage_command = options.carthage_command if sdk_integration_mode == :carthage
52
+
53
+ validate_sdk_addition options
54
+ end
55
+
56
+ def log
57
+ super
58
+ message = <<-EOF
59
+ <%= color('Xcode project:', BOLD) %> #{xcodeproj_path}
60
+ <%= color('Target:', BOLD) %> #{target.name}
61
+ <%= color('Live key:', BOLD) %> #{keys[:live] || '(none)'}
62
+ <%= color('Test key:', BOLD) %> #{keys[:test] || '(none)'}
63
+ <%= color('Domains:', BOLD) %> #{all_domains}
64
+ <%= color('URI scheme:', BOLD) %> #{uri_scheme || '(none)'}
65
+ <%= color('Podfile:', BOLD) %> #{podfile_path || '(none)'}
66
+ <%= color('Cartfile:', BOLD) %> #{cartfile_path || '(none)'}
67
+ <%= color('Carthage command:', BOLD) %> #{carthage_command || '(none)'}
68
+ <%= color('Pod repo update:', BOLD) %> #{pod_repo_update.inspect}
69
+ <%= color('Validate:', BOLD) %> #{validate.inspect}
70
+ <%= color('Force:', BOLD) %> #{force.inspect}
71
+ <%= color('Add SDK:', BOLD) %> #{add_sdk.inspect}
72
+ <%= color('Patch source:', BOLD) %> #{patch_source.inspect}
73
+ <%= color('Commit:', BOLD) %> #{commit.inspect}
74
+ <%= color('SDK integration mode:', BOLD) %> #{sdk_integration_mode || '(none)'}
75
+ EOF
76
+
77
+ if swift_version
78
+ message += <<-EOF
79
+ <%= color('Swift version:', BOLD) %> #{swift_version}
80
+ EOF
81
+ end
82
+
83
+ message += "\n"
84
+
85
+ say message
86
+ end
87
+
88
+ def validate_keys_from_setup_options(options)
89
+ live_key = options.live_key
90
+ test_key = options.test_key
91
+ @keys = {}
92
+ keys[:live] = live_key unless live_key.nil?
93
+ keys[:test] = test_key unless test_key.nil?
94
+
95
+ while @keys.empty?
96
+ say "A live key, a test key or both is required."
97
+ live_key = ask "Please enter your live Branch key or use --live_key [enter for none]: "
98
+ test_key = ask "Please enter your test Branch key or use --test_key [enter for none]: "
99
+
100
+ keys[:live] = live_key unless live_key == ""
101
+ keys[:test] = test_key unless test_key == ""
102
+ end
103
+ end
104
+
105
+ def validate_all_domains(options, required = true)
106
+ app_link_roots = app_link_roots_from_domains options.domains
107
+
108
+ unless options.app_link_subdomain.nil? || app_link_roots.include?(options.app_link_subdomain)
109
+ app_link_roots << options.app_link_subdomain
110
+ end
111
+
112
+ # app_link_roots now contains options.app_link_subdomain, if supplied, and the roots of any
113
+ # .app.link or .test-app.link domains provided via options.domains.
114
+
115
+ app_link_subdomains = app_link_subdomains_from_roots app_link_roots
116
+
117
+ custom_domains = custom_domains_from_domains options.domains
118
+
119
+ @all_domains = (app_link_subdomains + custom_domains).uniq
120
+
121
+ while required && @all_domains.empty?
122
+ domains = ask "Please enter domains as a comma-separated list: ", ->(str) { str.split "," }
123
+
124
+ @all_domains = all_domains_from_domains domains
125
+ end
126
+ end
127
+
128
+ def validate_uri_scheme(options)
129
+ # No validation at the moment. Just strips off any trailing ://
130
+ @uri_scheme = uri_scheme_without_suffix options.uri_scheme
131
+ end
132
+
133
+ def app_link_roots_from_domains(domains)
134
+ return [] if domains.nil?
135
+
136
+ domains.select { |d| d =~ APP_LINK_REGEXP }
137
+ .map { |d| d.sub(APP_LINK_REGEXP, '').sub(/-alternate$/, '') }
138
+ .uniq
139
+ end
140
+
141
+ def custom_domains_from_domains(domains)
142
+ return [] if domains.nil?
143
+ domains.reject { |d| d =~ APP_LINK_REGEXP }.uniq
144
+ end
145
+
146
+ def app_link_subdomains(root)
147
+ app_link_subdomain = root
148
+ return [] if app_link_subdomain.nil?
149
+
150
+ live_key = keys[:live]
151
+ test_key = keys[:test]
152
+
153
+ domains = []
154
+ unless live_key.nil?
155
+ domains += [
156
+ "#{app_link_subdomain}.app.link",
157
+ "#{app_link_subdomain}-alternate.app.link"
158
+ ]
159
+ end
160
+ unless test_key.nil?
161
+ domains += [
162
+ "#{app_link_subdomain}.test-app.link",
163
+ "#{app_link_subdomain}-alternate.test-app.link"
164
+ ]
165
+ end
166
+ domains
167
+ end
168
+
169
+ def app_link_subdomains_from_roots(roots)
170
+ roots.inject([]) { |domains, root| domains + app_link_subdomains(root) }
171
+ end
172
+
173
+ def all_domains_from_domains(domains)
174
+ app_link_roots = app_link_roots_from_domains domains
175
+ app_link_subdomains = app_link_subdomains_from_roots app_link_roots
176
+ custom_domains = custom_domains_from_domains domains
177
+ custom_domains + app_link_subdomains
178
+ end
179
+
180
+ # Removes any trailing :// from the argument and returns a copy
181
+ def uri_scheme_without_suffix(scheme)
182
+ return nil if scheme.nil?
183
+ scheme.sub %r{://$}, ""
184
+ end
185
+
186
+ def validate_sdk_addition(options)
187
+ return if !options.add_sdk || sdk_integration_mode
188
+
189
+ # If no CocoaPods or Carthage, check to see if the framework is linked.
190
+ target = helper.target_from_project xcodeproj, options.target
191
+ return if target.frameworks_build_phase.files.map(&:file_ref).map(&:path).any? { |p| p =~ /Branch.framework$/ }
192
+
193
+ # --podfile, --cartfile not specified. No Podfile found. No Cartfile found. No Branch.framework in project.
194
+ # Prompt the user:
195
+ selected = choose do |menu|
196
+ menu.header = "No Podfile or Cartfile specified or found. Here are your options"
197
+
198
+ SDK_OPTIONS.each_key { |k| menu.choice k }
199
+
200
+ menu.prompt = "What would you like to do?"
201
+ end
202
+
203
+ @sdk_integration_mode = SDK_OPTIONS[selected]
204
+
205
+ case sdk_integration_mode
206
+ when :cocoapods
207
+ @podfile_path = File.expand_path "../Podfile", xcodeproj_path
208
+ when :carthage
209
+ @cartfile_path = File.expand_path "../Cartfile", xcodeproj_path
210
+ @carthage_command = options.carthage_command
211
+ end
212
+ end
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,26 @@
1
+ module BranchIOCLI
2
+ module Configuration
3
+ class ValidateConfiguration < Configuration
4
+ attr_reader :domains
5
+
6
+ def initialize(options)
7
+ super
8
+ @domains = options.domains
9
+ end
10
+
11
+ def validate_options
12
+ validate_xcodeproj_path
13
+ validate_target
14
+ end
15
+
16
+ def log
17
+ super
18
+ say <<EOF
19
+ <%= color('Xcode project:', BOLD) %> #{xcodeproj_path}
20
+ <%= color('Target:', BOLD) %> #{target.name}
21
+ <%= color('Domains:', BOLD) %> #{domains || '(none)'}
22
+ EOF
23
+ end
24
+ end
25
+ end
26
+ end
@@ -7,7 +7,7 @@ class IO
7
7
  # object.
8
8
  #
9
9
  # :command: [String] a shell command to execute and report
10
- def report_command(command)
10
+ def log_command(command)
11
11
  write "$ #{command}\n\n"
12
12
 
13
13
  Open3.popen2e(command) do |stdin, output, thread|
@@ -32,7 +32,7 @@ end
32
32
  # Returns a Process::Status object.
33
33
  #
34
34
  # :command: [String] a shell command to execute and report
35
- def STDOUT.report_command(command)
35
+ def STDOUT.log_command(command)
36
36
  # TODO: Improve this implementation?
37
37
  say "<%= color(%q{$ #{command}}, [MAGENTA, BOLD]) %>\n\n"
38
38
  # May also write to stderr
@@ -1,2 +1,2 @@
1
1
  require "branch_io_cli/helper/branch_helper"
2
- require "branch_io_cli/helper/configuration_helper"
2
+ require "branch_io_cli/helper/patch_helper"
@@ -19,22 +19,6 @@ module BranchIOCLI
19
19
  @changes << change.to_s
20
20
  end
21
21
 
22
- # Shim around PatternPatch for now
23
- def apply_patch(options)
24
- modified = File.open(options[:files]) do |file|
25
- PatternPatch::Utilities.apply_patch file.read,
26
- options[:regexp],
27
- options[:text],
28
- options[:global],
29
- options[:mode],
30
- options[:offset] || 0
31
- end
32
-
33
- File.open(options[:files], "w") do |file|
34
- file.write modified
35
- end
36
- end
37
-
38
22
  def fetch(url)
39
23
  response = Net::HTTP.get_response URI(url)
40
24
 
@@ -2,10 +2,13 @@ require "json"
2
2
  require "net/http"
3
3
  require "openssl"
4
4
  require "pathname"
5
+ require "pattern_patch"
5
6
  require "plist"
7
+ require "shellwords"
6
8
  require "tmpdir"
7
9
  require "zip"
8
10
 
11
+ require "branch_io_cli/configuration"
9
12
  require "branch_io_cli/helper/methods"
10
13
 
11
14
  module BranchIOCLI
@@ -18,19 +21,23 @@ module BranchIOCLI
18
21
  PRODUCT_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER"
19
22
  RELEASE_CONFIGURATION = "Release"
20
23
 
24
+ def config
25
+ Configuration::Configuration.current
26
+ end
27
+
21
28
  def has_multiple_info_plists?
22
- ConfigurationHelper.xcodeproj.build_configurations.inject([]) do |files, config|
23
- files + [expanded_build_setting(ConfigurationHelper.target, "INFOPLIST_FILE", config.name)]
29
+ config.xcodeproj.build_configurations.inject([]) do |files, c|
30
+ files + [expanded_build_setting(config.target, "INFOPLIST_FILE", c.name)]
24
31
  end.uniq.count > 1
25
32
  end
26
33
 
27
34
  def add_keys_to_info_plist(keys)
28
35
  if has_multiple_info_plists?
29
- ConfigurationHelper.xcodeproj.build_configurations.each do |config|
30
- update_info_plist_setting config.name do |info_plist|
36
+ config.xcodeproj.build_configurations.each do |c|
37
+ update_info_plist_setting c.name do |info_plist|
31
38
  if keys.count > 1
32
39
  # Use test key in debug configs and live key in release configs
33
- info_plist["branch_key"] = config.debug? ? keys[:test] : keys[:live]
40
+ info_plist["branch_key"] = c.debug? ? keys[:test] : keys[:live]
34
41
  else
35
42
  info_plist["branch_key"] = keys[:live] ? keys[:live] : keys[:test]
36
43
  end
@@ -54,21 +61,21 @@ module BranchIOCLI
54
61
  # Add all supplied domains unless all are app.link domains.
55
62
  return if domains.all? { |d| d =~ /app\.link$/ }
56
63
 
57
- ConfigurationHelper.xcodeproj.build_configurations.each do |config|
58
- update_info_plist_setting config.name do |info_plist|
64
+ config.xcodeproj.build_configurations.each do |c|
65
+ update_info_plist_setting c.name do |info_plist|
59
66
  info_plist["branch_universal_link_domains"] = domains
60
67
  end
61
68
  end
62
69
  end
63
70
 
64
71
  def ensure_uri_scheme_in_info_plist
65
- uri_scheme = ConfigurationHelper.uri_scheme
72
+ uri_scheme = config.uri_scheme
66
73
 
67
74
  # No URI scheme specified. Do nothing.
68
75
  return if uri_scheme.nil?
69
76
 
70
- ConfigurationHelper.xcodeproj.build_configurations.each do |config|
71
- update_info_plist_setting config.name do |info_plist|
77
+ config.xcodeproj.build_configurations.each do |c|
78
+ update_info_plist_setting c.name do |info_plist|
72
79
  url_types = info_plist["CFBundleURLTypes"] || []
73
80
  uri_schemes = url_types.inject([]) { |schemes, t| schemes + t["CFBundleURLSchemes"] }
74
81
 
@@ -89,11 +96,11 @@ module BranchIOCLI
89
96
 
90
97
  def update_info_plist_setting(configuration = RELEASE_CONFIGURATION, &b)
91
98
  # find the Info.plist paths for this configuration
92
- info_plist_path = expanded_build_setting ConfigurationHelper.target, "INFOPLIST_FILE", configuration
99
+ info_plist_path = expanded_build_setting config.target, "INFOPLIST_FILE", configuration
93
100
 
94
101
  raise "Info.plist not found for configuration #{configuration}" if info_plist_path.nil?
95
102
 
96
- project_parent = File.dirname ConfigurationHelper.xcodeproj_path
103
+ project_parent = File.dirname config.xcodeproj_path
97
104
 
98
105
  info_plist_path = File.expand_path info_plist_path, project_parent
99
106
 
@@ -108,8 +115,8 @@ module BranchIOCLI
108
115
  end
109
116
 
110
117
  def add_universal_links_to_project(domains, remove_existing, configuration = RELEASE_CONFIGURATION)
111
- project = ConfigurationHelper.xcodeproj
112
- target = ConfigurationHelper.target
118
+ project = config.xcodeproj
119
+ target = config.target
113
120
 
114
121
  relative_entitlements_path = expanded_build_setting target, CODE_SIGN_ENTITLEMENTS, configuration
115
122
  project_parent = File.dirname project.path
@@ -168,7 +175,7 @@ module BranchIOCLI
168
175
  team, bundle = team_and_bundle_from_app_id identifier
169
176
 
170
177
  update_team_and_bundle_ids team, bundle
171
- add_change ConfigurationHelper.xcodeproj_path
178
+ add_change config.xcodeproj_path
172
179
  end
173
180
 
174
181
  def validate_team_and_bundle_ids_from_aasa_files(domains = [], remove_existing = false, configuration = RELEASE_CONFIGURATION)
@@ -282,7 +289,7 @@ module BranchIOCLI
282
289
  end
283
290
 
284
291
  def validate_team_and_bundle_ids(domain, configuration)
285
- target = ConfigurationHelper.target
292
+ target = config.target
286
293
 
287
294
  product_bundle_identifier = expanded_build_setting target, PRODUCT_BUNDLE_IDENTIFIER, configuration
288
295
  development_team = expanded_build_setting target, DEVELOPMENT_TEAM, configuration
@@ -321,7 +328,7 @@ module BranchIOCLI
321
328
  end
322
329
 
323
330
  def update_team_and_bundle_ids(team, bundle)
324
- target = ConfigurationHelper.target
331
+ target = config.target
325
332
 
326
333
  target.build_configuration_list.set_setting PRODUCT_BUNDLE_IDENTIFIER, bundle
327
334
  target.build_configuration_list.set_setting DEVELOPMENT_TEAM, team
@@ -347,8 +354,8 @@ module BranchIOCLI
347
354
  end
348
355
 
349
356
  def domains_from_project(configuration = RELEASE_CONFIGURATION)
350
- project = ConfigurationHelper.xcodeproj
351
- target = ConfigurationHelper.target
357
+ project = config.xcodeproj
358
+ target = config.target
352
359
 
353
360
  relative_entitlements_path = expanded_build_setting target, CODE_SIGN_ENTITLEMENTS, configuration
354
361
  return [] if relative_entitlements_path.nil?
@@ -381,438 +388,40 @@ module BranchIOCLI
381
388
  setting_value
382
389
  end
383
390
 
384
- def patch_app_delegate_swift(project)
385
- app_delegate_swift = project.files.find { |f| f.path =~ /AppDelegate.swift$/ }
386
- return false if app_delegate_swift.nil?
387
-
388
- app_delegate_swift_path = app_delegate_swift.real_path.to_s
389
-
390
- app_delegate = File.read app_delegate_swift_path
391
- return false if app_delegate =~ /import\s+Branch/
392
-
393
- say "Patching #{app_delegate_swift_path}"
394
-
395
- apply_patch(
396
- files: app_delegate_swift_path,
397
- regexp: /^\s*import .*$/,
398
- text: "\nimport Branch",
399
- mode: :prepend
400
- )
401
-
402
- patch_did_finish_launching_method_swift app_delegate_swift_path
403
- patch_continue_user_activity_method_swift app_delegate_swift_path
404
- patch_open_url_method_swift app_delegate_swift_path
405
-
406
- add_change app_delegate_swift_path
407
- true
408
- end
409
-
410
- def patch_app_delegate_objc(project)
411
- app_delegate_objc = project.files.find { |f| f.path =~ /AppDelegate.m$/ }
412
- return false if app_delegate_objc.nil?
413
-
414
- app_delegate_objc_path = app_delegate_objc.real_path.to_s
415
-
416
- app_delegate = File.read app_delegate_objc_path
417
- return false if app_delegate =~ %r{^\s+#import\s+<Branch/Branch.h>|^\s+@import\s+Branch;}
418
-
419
- say "Patching #{app_delegate_objc_path}"
420
-
421
- apply_patch(
422
- files: app_delegate_objc_path,
423
- regexp: /^\s+@import|^\s+#import.*$/,
424
- text: "\n#import <Branch/Branch.h>",
425
- mode: :prepend
426
- )
427
-
428
- patch_did_finish_launching_method_objc app_delegate_objc_path
429
- patch_continue_user_activity_method_objc app_delegate_objc_path
430
- patch_open_url_method_objc app_delegate_objc_path
431
-
432
- add_change app_delegate_objc_path
433
- true
434
- end
435
-
436
- def patch_did_finish_launching_method_swift(app_delegate_swift_path)
437
- app_delegate_swift = File.read app_delegate_swift_path
438
-
439
- if app_delegate_swift =~ /didFinishLaunching[^\n]+?\{/m
440
- # method already present
441
- init_session_text = ConfigurationHelper.keys.count <= 1 || has_multiple_info_plists? ? "" : <<EOF
442
- #if DEBUG
443
- Branch.setUseTestBranchKey(true)
444
- #endif
445
-
446
- EOF
447
-
448
- init_session_text += <<-EOF
449
- Branch.getInstance().initSession(launchOptions: launchOptions) {
450
- universalObject, linkProperties, error in
451
-
452
- // TODO: Route Branch links
453
- }
454
- EOF
455
-
456
- apply_patch(
457
- files: app_delegate_swift_path,
458
- regexp: /didFinishLaunchingWithOptions.*?\{[^\n]*\n/m,
459
- text: init_session_text,
460
- mode: :append
461
- )
462
- else
463
- # method not present. add entire method
464
-
465
- method_text = <<EOF
466
-
467
- func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
468
- EOF
469
-
470
- if ConfigurationHelper.keys.count > 1 && !has_multiple_info_plists?
471
- method_text += <<EOF
472
- #if DEBUG
473
- Branch.setUseTestBranchKey(true)
474
- #endif
475
-
476
- EOF
477
- end
478
-
479
- method_text += <<-EOF
480
- Branch.getInstance().initSession(launchOptions: launchOptions) {
481
- universalObject, linkProperties, error in
482
-
483
- // TODO: Route Branch links
484
- }
485
- return true
486
- }
487
- EOF
488
-
489
- apply_patch(
490
- files: app_delegate_swift_path,
491
- regexp: /var\s+window\s?:\s?UIWindow\?.*?\n/m,
492
- text: method_text,
493
- mode: :append
494
- )
495
- end
496
- end
497
-
498
- def patch_did_finish_launching_method_objc(app_delegate_objc_path)
499
- app_delegate_objc = File.read app_delegate_objc_path
500
-
501
- if app_delegate_objc =~ /didFinishLaunchingWithOptions/m
502
- # method exists. patch it.
503
- init_session_text = ConfigurationHelper.keys.count <= 1 || has_multiple_info_plists? ? "" : <<EOF
504
- #ifdef DEBUG
505
- [Branch setUseTestBranchKey:YES];
506
- #endif // DEBUG
507
-
508
- EOF
509
-
510
- init_session_text += <<-EOF
511
- [[Branch getInstance] initSessionWithLaunchOptions:launchOptions
512
- andRegisterDeepLinkHandlerUsingBranchUniversalObject:^(BranchUniversalObject *universalObject, BranchLinkProperties *linkProperties, NSError *error){
513
- // TODO: Route Branch links
514
- }];
515
- EOF
516
-
517
- apply_patch(
518
- files: app_delegate_objc_path,
519
- regexp: /didFinishLaunchingWithOptions.*?\{[^\n]*\n/m,
520
- text: init_session_text,
521
- mode: :append
522
- )
523
- else
524
- # method does not exist. add it.
525
- method_text = <<EOF
526
-
527
- - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
528
- EOF
529
-
530
- if ConfigurationHelper.keys.count > 1 && !has_multiple_info_plists?
531
- method_text += <<EOF
532
- #ifdef DEBUG
533
- [Branch setUseTestBranchKey:YES];
534
- #endif // DEBUG
535
-
536
- EOF
537
- end
538
-
539
- method_text += <<-EOF
540
- [[Branch getInstance] initSessionWithLaunchOptions:launchOptions
541
- andRegisterDeepLinkHandlerUsingBranchUniversalObject:^(BranchUniversalObject *universalObject, BranchLinkProperties *linkProperties, NSError *error){
542
- // TODO: Route Branch links
543
- }];
544
- return YES;
545
- }
546
- EOF
547
-
548
- apply_patch(
549
- files: app_delegate_objc_path,
550
- regexp: /^@implementation.*?\n/m,
551
- text: method_text,
552
- mode: :append
553
- )
554
- end
555
- end
556
-
557
- def patch_open_url_method_swift(app_delegate_swift_path)
558
- app_delegate_swift = File.read app_delegate_swift_path
559
- if app_delegate_swift =~ /application.*open\s+url.*options/
560
- # Has application:openURL:options:
561
- open_url_text = <<-EOF
562
- // TODO: Adjust your method as you see fit.
563
- if Branch.getInstance().application(app, open: url, options: options) {
564
- return true
565
- }
566
-
567
- EOF
568
-
569
- apply_patch(
570
- files: app_delegate_swift_path,
571
- regexp: /application.*open\s+url.*options:.*?\{.*?\n/m,
572
- text: open_url_text,
573
- mode: :append
574
- )
575
- elsif app_delegate_swift =~ /application.*open\s+url.*sourceApplication/
576
- # Has application:openURL:sourceApplication:annotation:
577
- # TODO: This method is deprecated.
578
- open_url_text = <<-EOF
579
- // TODO: Adjust your method as you see fit.
580
- if Branch.getInstance().application(application, open: url, sourceApplication: sourceApplication, annotation: annotation) {
581
- return true
582
- }
583
-
584
- EOF
585
-
586
- apply_patch(
587
- files: app_delegate_swift_path,
588
- regexp: /application.*open\s+url.*sourceApplication:.*?\{.*?\n/m,
589
- text: open_url_text,
590
- mode: :append
591
- )
592
- else
593
- # Has neither
594
- open_url_text = <<EOF
595
-
596
-
597
- func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
598
- return Branch.getInstance().application(app, open: url, options: options)
599
- }
600
- EOF
601
-
602
- apply_patch(
603
- files: app_delegate_swift_path,
604
- regexp: /\n\s*\}[^{}]*\Z/m,
605
- text: open_url_text,
606
- mode: :prepend
607
- )
608
- end
609
- end
610
-
611
- def patch_continue_user_activity_method_swift(app_delegate_swift_path)
612
- app_delegate = File.read app_delegate_swift_path
613
- if app_delegate =~ /application:.*continue userActivity:.*restorationHandler:/
614
- # Add something to the top of the method
615
- continue_user_activity_text = <<-EOF
616
- // TODO: Adjust your method as you see fit.
617
- if Branch.getInstance.continue(userActivity) {
618
- return true
619
- }
620
-
621
- EOF
622
-
623
- apply_patch(
624
- files: app_delegate_swift_path,
625
- regexp: /application:.*continue userActivity:.*restorationHandler:.*?\{.*?\n/m,
626
- text: continue_user_activity_text,
627
- mode: :append
628
- )
629
- else
630
- # Add the application:continueUserActivity:restorationHandler method if it does not exist
631
- continue_user_activity_text = <<-EOF
632
-
633
-
634
- func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
635
- return Branch.getInstance().continue(userActivity)
636
- }
637
- EOF
638
-
639
- apply_patch(
640
- files: app_delegate_swift_path,
641
- regexp: /\n\s*\}[^{}]*\Z/m,
642
- text: continue_user_activity_text,
643
- mode: :prepend
644
- )
645
- end
646
- end
647
-
648
- def patch_open_url_method_objc(app_delegate_objc_path)
649
- app_delegate_objc = File.read app_delegate_objc_path
650
- if app_delegate_objc =~ /application:.*openURL:.*options/
651
- # Has application:openURL:options:
652
- open_url_text = <<-EOF
653
- // TODO: Adjust your method as you see fit.
654
- if ([[Branch getInstance] application:app openURL:url options:options]) {
655
- return YES;
656
- }
657
-
658
- EOF
659
-
660
- apply_patch(
661
- files: app_delegate_objc_path,
662
- regexp: /application:.*openURL:.*options:.*?\{.*?\n/m,
663
- text: open_url_text,
664
- mode: :append
665
- )
666
- elsif app_delegate_objc =~ /application:.*openURL:.*sourceApplication/
667
- # Has application:openURL:sourceApplication:annotation:
668
- open_url_text = <<-EOF
669
- // TODO: Adjust your method as you see fit.
670
- if ([[Branch getInstance] application:application openURL:url sourceApplication:sourceApplication annotation:annotation]) {
671
- return YES;
672
- }
673
-
674
- EOF
675
-
676
- apply_patch(
677
- files: app_delegate_objc_path,
678
- regexp: /application:.*openURL:.*sourceApplication:.*?\{.*?\n/m,
679
- text: open_url_text,
680
- mode: :append
681
- )
682
- else
683
- # Has neither
684
- open_url_text = <<-EOF
685
-
686
-
687
- - (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options
688
- {
689
- return [[Branch getInstance] application:app openURL:url options:options];
690
- }
691
- EOF
692
-
693
- apply_patch(
694
- files: app_delegate_objc_path,
695
- regexp: /\n\s*@end[^@]*\Z/m,
696
- text: open_url_text,
697
- mode: :prepend
698
- )
699
- end
700
- end
701
-
702
- def patch_continue_user_activity_method_objc(app_delegate_objc_path)
703
- app_delegate = File.read app_delegate_objc_path
704
- if app_delegate =~ /application:.*continueUserActivity:.*restorationHandler:/
705
- continue_user_activity_text = <<-EOF
706
- // TODO: Adjust your method as you see fit.
707
- if ([[Branch getInstance] continueUserActivity:userActivity]) {
708
- return YES;
709
- }
710
-
711
- EOF
712
-
713
- apply_patch(
714
- files: app_delegate_objc_path,
715
- regexp: /application:.*continueUserActivity:.*restorationHandler:.*?\{.*?\n/m,
716
- text: continue_user_activity_text,
717
- mode: :append
718
- )
719
- else
720
- # Add the application:continueUserActivity:restorationHandler method if it does not exist
721
- continue_user_activity_text = <<-EOF
722
-
723
-
724
- - (BOOL)application:(UIApplication *)app continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * _Nullable))restorationHandler
725
- {
726
- return [[Branch getInstance] continueUserActivity:userActivity];
727
- }
728
- EOF
729
-
730
- apply_patch(
731
- files: app_delegate_objc_path,
732
- regexp: /\n\s*@end[^@]*\Z/m,
733
- text: continue_user_activity_text,
734
- mode: :prepend
735
- )
736
- end
737
- end
738
-
739
- def patch_podfile(podfile_path)
740
- podfile = File.read podfile_path
741
-
742
- # Podfile already contains the Branch pod
743
- # TODO: Allow for adding to multiple targets in the Podfile
744
- return false if podfile =~ /pod\s+('Branch'|"Branch")/
745
-
746
- say "Adding pod \"Branch\" to #{podfile_path}"
747
-
748
- if podfile =~ /target\s+(["'])#{ConfigurationHelper.target.name}\1\s+do.*?\n/m
749
- # if there is a target block for this target:
750
- apply_patch(
751
- files: podfile_path,
752
- regexp: /\n(\s*)target\s+(["'])#{ConfigurationHelper.target.name}\2\s+do.*?\n/m,
753
- text: "\\1 pod \"Branch\"\n",
754
- mode: :append
755
- )
756
- else
757
- # add to the abstract_target for this target
758
- apply_patch(
759
- files: podfile_path,
760
- regexp: /^(\s*)target\s+["']#{ConfigurationHelper.target.name}/,
761
- text: "\\1pod \"Branch\"\n",
762
- mode: :prepend
763
- )
764
- end
765
-
766
- true
767
- end
768
-
769
- def patch_cartfile(cartfile_path)
770
- cartfile = File.read cartfile_path
771
-
772
- # Cartfile already contains the Branch framework
773
- return false if cartfile =~ /git.+Branch/
774
-
775
- say "Adding \"Branch\" to #{cartfile_path}"
776
-
777
- apply_patch(
778
- files: cartfile_path,
779
- regexp: /\z/,
780
- text: "github \"BranchMetrics/ios-branch-deep-linking\"\n",
781
- mode: :append
782
- )
783
-
784
- true
785
- end
786
-
787
391
  def add_cocoapods(options)
788
392
  verify_cocoapods
789
393
 
790
- podfile_path = ConfigurationHelper.podfile_path
394
+ podfile_path = config.podfile_path
791
395
 
792
396
  install_command = "pod install"
793
397
  install_command += " --repo-update" if options.pod_repo_update
794
398
  Dir.chdir(File.dirname(podfile_path)) do
795
399
  sh "pod init"
796
- apply_patch(
797
- files: podfile_path,
798
- regexp: /^(\s*)# Pods for #{ConfigurationHelper.target.name}$/,
400
+ PatternPatch::Patch.new(
401
+ regexp: /^(\s*)# Pods for #{config.target.name}$/,
799
402
  mode: :append,
800
- text: "\n\\1pod \"Branch\"",
801
- global: false
802
- )
403
+ text: "\n\\1pod \"Branch\""
404
+ ).apply podfile_path
803
405
  sh install_command
804
406
  end
805
407
 
408
+ return unless config.commit
409
+
806
410
  add_change podfile_path
807
411
  add_change "#{podfile_path}.lock"
808
412
 
809
413
  # For now, add Pods folder to SCM.
810
414
  pods_folder_path = Pathname.new(File.expand_path("../Pods", podfile_path)).relative_path_from Pathname.pwd
811
- workspace_path = Pathname.new(File.expand_path(ConfigurationHelper.xcodeproj_path.sub(/.xcodeproj$/, ".xcworkspace"))).relative_path_from Pathname.pwd
415
+ workspace_path = Pathname.new(File.expand_path(config.xcodeproj_path.sub(/.xcodeproj$/, ".xcworkspace"))).relative_path_from Pathname.pwd
812
416
  podfile_pathname = Pathname.new(podfile_path).relative_path_from Pathname.pwd
813
417
  add_change pods_folder_path
814
418
  add_change workspace_path
815
- sh "git add #{podfile_pathname} #{podfile_pathname}.lock #{pods_folder_path} #{workspace_path}" if options.commit
419
+
420
+ cmd = "git add #{Shellwords.escape(podfile_pathname)} " \
421
+ "#{Shellwords.escape(podfile_pathname)}.lock " \
422
+ "#{Shellwords.escape(pods_folder_path)} " \
423
+ "#{Shellwords.escape(workspace_path)}"
424
+ sh cmd
816
425
  end
817
426
 
818
427
  def add_carthage(options)
@@ -820,7 +429,7 @@ EOF
820
429
  verify_carthage
821
430
 
822
431
  # 1. Generate Cartfile
823
- cartfile_path = ConfigurationHelper.cartfile_path
432
+ cartfile_path = config.cartfile_path
824
433
  File.open(cartfile_path, "w") do |file|
825
434
  file.write <<EOF
826
435
  github "BranchMetrics/ios-branch-deep-linking"
@@ -829,18 +438,18 @@ EOF
829
438
 
830
439
  # 2. carthage update
831
440
  Dir.chdir(File.dirname(cartfile_path)) do
832
- sh "carthage #{ConfigurationHelper.carthage_command}"
441
+ sh "carthage #{config.carthage_command}"
833
442
  end
834
443
 
835
444
  # 3. Add Cartfile and Cartfile.resolved to commit (in case :commit param specified)
836
445
  add_change cartfile_path
837
446
  add_change "#{cartfile_path}.resolved"
838
- add_change ConfigurationHelper.xcodeproj_path
447
+ add_change config.xcodeproj_path
839
448
 
840
449
  # 4. Add to target dependencies
841
- frameworks_group = ConfigurationHelper.xcodeproj.frameworks_group
450
+ frameworks_group = config.xcodeproj.frameworks_group
842
451
  branch_framework = frameworks_group.new_file "Carthage/Build/iOS/Branch.framework"
843
- target = ConfigurationHelper.target
452
+ target = config.target
844
453
  target.frameworks_build_phase.add_file_reference branch_framework
845
454
 
846
455
  # 5. Create a copy-frameworks build phase
@@ -850,7 +459,11 @@ EOF
850
459
  carthage_build_phase.input_paths << "$(SRCROOT)/Carthage/Build/iOS/Branch.framework"
851
460
  carthage_build_phase.output_paths << "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Branch.framework"
852
461
 
853
- ConfigurationHelper.xcodeproj.save
462
+ update_framework_search_paths "$(SRCROOT)/Carthage/Build/iOS"
463
+
464
+ config.xcodeproj.save
465
+
466
+ return unless config.commit
854
467
 
855
468
  # For now, add Carthage folder to SCM
856
469
 
@@ -858,12 +471,15 @@ EOF
858
471
  carthage_folder_path = Pathname.new(File.expand_path("../Carthage", cartfile_path)).relative_path_from(Pathname.pwd)
859
472
  cartfile_pathname = Pathname.new(cartfile_path).relative_path_from Pathname.pwd
860
473
  add_change carthage_folder_path
861
- sh "git add #{cartfile_pathname} #{cartfile_pathname}.resolved #{carthage_folder_path}" if options.commit
474
+ cmd = "git add #{Shellwords.escape(cartfile_pathname)} " \
475
+ "#{Shellwords.escape(cartfile_pathname)}.resolved " \
476
+ "#{Shellwords.escape(carthage_folder_path)}"
477
+ sh cmd
862
478
  end
863
479
 
864
480
  def add_direct(options)
865
481
  # Put the framework in the path for any existing Frameworks group in the project.
866
- frameworks_group = ConfigurationHelper.xcodeproj.frameworks_group
482
+ frameworks_group = config.xcodeproj.frameworks_group
867
483
  framework_path = File.join frameworks_group.real_path, "Branch.framework"
868
484
  raise "#{framework_path} exists." if File.exist? framework_path
869
485
 
@@ -901,40 +517,47 @@ EOF
901
517
 
902
518
  # Now the current framework is in framework_path
903
519
 
904
- say "Adding to #{ConfigurationHelper.xcodeproj_path}"
520
+ say "Adding to #{config.xcodeproj_path}"
905
521
 
906
522
  # Add as a dependency in the Frameworks group
907
523
  framework = frameworks_group.new_file "Branch.framework" # relative to frameworks_group.real_path
908
- ConfigurationHelper.target.frameworks_build_phase.add_file_reference framework, true
524
+ config.target.frameworks_build_phase.add_file_reference framework, true
909
525
 
910
- # Make sure this is in the FRAMEWORK_SEARCH_PATHS if we just added it.
911
- if frameworks_group.files.count == 1
912
- ConfigurationHelper.target.build_configurations.each do |config|
913
- paths = config.build_settings["FRAMEWORK_SEARCH_PATHS"] || []
914
- next if paths.any? { |p| p == '$(SRCROOT)' || p == '$(SRCROOT)/**' }
915
- paths << '$(SRCROOT)'
916
- config.build_settings["FRAMEWORK_SEARCH_PATHS"] = paths
917
- end
918
- end
919
- # If it already existed, it's almost certainly already in FRAMEWORK_SEARCH_PATHS.
526
+ update_framework_search_paths "$(SRCROOT)"
920
527
 
921
- ConfigurationHelper.xcodeproj.save
528
+ config.xcodeproj.save
922
529
 
923
- add_change ConfigurationHelper.xcodeproj_path
530
+ add_change config.xcodeproj_path
924
531
  add_change framework_path
925
- sh "git add #{framework_path}" if options.commit
532
+ sh "git add #{Shellwords.escape(framework_path)}" if options.commit
926
533
 
927
534
  say "Done. ✅"
928
535
  end
929
536
 
537
+ def update_framework_search_paths(path)
538
+ # Make sure this is in the FRAMEWORK_SEARCH_PATHS if we just added it.
539
+ if config.xcodeproj.frameworks_group.files.count == 1
540
+ target = config.target
541
+ target.build_configurations.each do |c|
542
+ # this accounts for project-level settings as well
543
+ setting = target.resolved_build_setting("FRAMEWORK_SEARCH_PATHS")[c.name] || []
544
+ next if setting.include?(path) || setting.include?("#{path}/**")
545
+ setting << path
546
+
547
+ c.build_settings["FRAMEWORK_SEARCH_PATHS"] = setting
548
+ end
549
+ end
550
+ # If it already existed, it's almost certainly already in FRAMEWORK_SEARCH_PATHS.
551
+ end
552
+
930
553
  def update_podfile(options)
931
554
  verify_cocoapods
932
555
 
933
- podfile_path = ConfigurationHelper.podfile_path
556
+ podfile_path = config.podfile_path
934
557
  return false if podfile_path.nil?
935
558
 
936
559
  # 1. Patch Podfile. Return if no change (Branch pod already present).
937
- return false unless patch_podfile podfile_path
560
+ return false unless PatchHelper.patch_podfile podfile_path
938
561
 
939
562
  # 2. pod install
940
563
  # command = "PATH='#{ENV['PATH']}' pod install"
@@ -956,7 +579,7 @@ EOF
956
579
 
957
580
  # 5. If so, add the Pods folder to the commit (in case :commit param specified)
958
581
  add_change pods_folder_path
959
- sh "git add #{pods_folder_path}" if options.commit
582
+ sh "git add #{Shellwords.escape(pods_folder_path)}" if options.commit
960
583
 
961
584
  true
962
585
  end
@@ -964,26 +587,26 @@ EOF
964
587
  def update_cartfile(options, project)
965
588
  verify_carthage
966
589
 
967
- cartfile_path = ConfigurationHelper.cartfile_path
590
+ cartfile_path = config.cartfile_path
968
591
  return false if cartfile_path.nil?
969
592
 
970
593
  # 1. Patch Cartfile. Return if no change (Branch already present).
971
- return false unless patch_cartfile cartfile_path
594
+ return false unless PatchHelper.patch_cartfile cartfile_path
972
595
 
973
596
  # 2. carthage update
974
597
  Dir.chdir(File.dirname(cartfile_path)) do
975
- sh "carthage #{ConfigurationHelper.carthage_command}"
598
+ sh "carthage #{config.carthage_command}"
976
599
  end
977
600
 
978
601
  # 3. Add Cartfile and Cartfile.resolved to commit (in case :commit param specified)
979
602
  add_change cartfile_path
980
603
  add_change "#{cartfile_path}.resolved"
981
- add_change ConfigurationHelper.xcodeproj_path
604
+ add_change config.xcodeproj_path
982
605
 
983
606
  # 4. Add to target dependencies
984
607
  frameworks_group = project.frameworks_group
985
608
  branch_framework = frameworks_group.new_file "Carthage/Build/iOS/Branch.framework"
986
- target = ConfigurationHelper.target
609
+ target = config.target
987
610
  target.frameworks_build_phase.add_file_reference branch_framework
988
611
 
989
612
  # 5. Add to copy-frameworks build phase
@@ -1003,15 +626,11 @@ EOF
1003
626
 
1004
627
  # 7. If so, add the Carthage folder to the commit (in case :commit param specified)
1005
628
  add_change carthage_folder_path
1006
- sh "git add #{carthage_folder_path}" if options.commit
629
+ sh "git add #{Shellwords.escape(carthage_folder_path)}" if options.commit
1007
630
 
1008
631
  true
1009
632
  end
1010
633
 
1011
- def patch_source(xcodeproj)
1012
- patch_app_delegate_swift(xcodeproj) || patch_app_delegate_objc(xcodeproj)
1013
- end
1014
-
1015
634
  def verify_cocoapods
1016
635
  pod_cmd = `which pod`
1017
636
  return unless pod_cmd.empty?
@@ -1059,7 +678,7 @@ EOF
1059
678
  end
1060
679
 
1061
680
  def verify_git
1062
- return unless ConfigurationHelper.commit
681
+ return unless config.commit
1063
682
 
1064
683
  git_cmd = `which git`
1065
684
  return unless git_cmd.empty?