branch_io_cli 0.6.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6369e446a2ef359946dccb3b93132c75c6ed72c0
4
- data.tar.gz: 53affe0e6938179ea185381d139cb18b0c8105d4
3
+ metadata.gz: b12805e82fb366c82741249dfbe0b186dd453cd6
4
+ data.tar.gz: beed4c107749da36ab0c36d31dfb77d544a083e8
5
5
  SHA512:
6
- metadata.gz: 99149f86b892a1aaed05a04e221455409c40cf6fd7f97d2fddac0dbfef368cf6ea4d159bd10511bb03e49bf0ba50e00a5df6ef35170ed9f9de86f0fb135b66b2
7
- data.tar.gz: 0c3cd173bc20634d51c9469b3b286dab4e49582e1c16588648850c354683cc3c380717cbd1684c760ebc9d58f5b68a595773b25e5069d5f9813a32b54ce4ece6
6
+ metadata.gz: 88ce57d3ee76c932ec1df8fea6befa753a864753f9d741d4b779b5d545e840b89af98a921e238f345a00878375678f707576185d9f22c14bdbd356c250e3057f
7
+ data.tar.gz: b5a0b49080a5213523461e43ee3595bfa7a874d7de528ce4eca98e6b15efa0d240d062ad475f33e35229efb9cdad5dadcf5e5fae32d7fa24bb808bd38ca9ef55
data/README.md CHANGED
@@ -28,6 +28,7 @@ Note that this command may require `sudo` access if you are using the system Rub
28
28
  branch_io -h
29
29
  branch_io setup -h
30
30
  branch_io validate -h
31
+ branch_io report -h
31
32
  ```
32
33
 
33
34
  ### Shell completion
@@ -103,10 +104,10 @@ Before using this command, make sure to set up your app in the [Branch Dashboard
103
104
  - Domain name(s) used for Branch links
104
105
  - Location of your Xcode project (may be inferred in simple projects)
105
106
 
106
- To use the `--commit` option, you must have the `git` command available in your path.
107
-
108
- To add the SDK with CocoaPods or Carthage, you must have the `pod` or `carthage`
109
- command, respectively, available in your path.
107
+ If using the `--commit` option, `git` is required. If not using `--no-add-sdk`,
108
+ the `pod` or `carthage` command may be required. If not found, the CLI will
109
+ offer to install and set up these command-line tools for you. Alternately, you can arrange
110
+ that the relevant commands are available in your `PATH`.
110
111
 
111
112
  #### Options
112
113
 
@@ -124,6 +125,7 @@ command, respectively, available in your path.
124
125
  |--target MyAppTarget|Name of a target to modify in the Xcode project|
125
126
  |--podfile /path/to/Podfile|Path to the Podfile for the project|
126
127
  |--cartfile /path/to/Cartfile|Path to the Cartfile for the project|
128
+ |--carthage-command <command>|Command to use when installing from Carthage (default: update --platform ios)|
127
129
  |--frameworks AdSupport,CoreSpotlight,SafariServices|Comma-separated list of system frameworks to add to the project|
128
130
  |--[no-]pod-repo-update|Update the local podspec repo before installing (default: yes)|
129
131
  |--[no-]validate|Validate Universal Link configuration (default: yes)|
@@ -162,6 +164,12 @@ branch_io setup -D myapp.app.link,example.com,www.example.com
162
164
  branch_io setup --no-pod-repo-update
163
165
  ```
164
166
 
167
+ ##### Install using carthage bootstrap
168
+
169
+ ```bash
170
+ branch_io --carthage-command "bootstrap --no-use-binaries"
171
+ ```
172
+
165
173
  ### Validate command
166
174
 
167
175
  ```bash
@@ -12,7 +12,7 @@ _branch_io_complete()
12
12
  global_opts="-h --help -t --trace -v --version"
13
13
 
14
14
  setup_opts="$global_opts -L --live-key -T --test-key -D --domains --app-link-subdomain -U --uri-scheme"
15
- setup_opts="$setup_opts --xcodeproj --target --frameworks --podfile --cartfile"
15
+ setup_opts="$setup_opts --xcodeproj --target --frameworks --podfile --cartfile --carthage-command"
16
16
  # Don't autocomplete the default values here, e.g. --no-force, --pod-repo-update.
17
17
  setup_opts="$setup_opts --no-add-sdk --no-validate --force --no-pod-repo-update --commit --no-patch-source"
18
18
 
@@ -5,7 +5,7 @@ _branch_io_complete() {
5
5
  word="$1"
6
6
  opts="-h --help -t --trace -v --version"
7
7
  opts="$opts -L --live-key -T --test-key -D --domains --app-link-subdomain -U --uri-scheme"
8
- opts="$opts --xcodeproj --target --frameworks --podfile --cartfile"
8
+ opts="$opts --xcodeproj --target --frameworks --podfile --cartfile --carthage-command"
9
9
  # Don't autocomplete the default values here, e.g. --no-force, --pod-repo-update.
10
10
  opts="$opts --no-add-sdk --no-validate --force --no-pod-repo-update --commit --no-patch-source"
11
11
 
@@ -58,10 +58,10 @@ for details. To use the <%= color('setup', BOLD) %> command, you need:
58
58
  - Domain name(s) used for Branch links
59
59
  - Location of your Xcode project (may be inferred in simple projects)
60
60
 
61
- To use the <%= color('--commit', BOLD) %> option, you must have the <%= color('git', BOLD) %> command available in your path.
62
-
63
- To add the SDK with CocoaPods or Carthage, you must have the <%= color('pod', BOLD) %> or <%= color('carthage', BOLD) %>
64
- command, respectively, available in your path.
61
+ If using the <%= color('--commit', BOLD) %> option, <%= color('git', BOLD) %> is required. If not using <%= color('--no-add-sdk', BOLD) %>,
62
+ the <%= color('pod', BOLD) %> or <%= color('carthage', BOLD) %> command may be required. If not found, the CLI will
63
+ offer to install and set up these command-line tools for you. Alternately, you can arrange
64
+ that the relevant commands are available in your <%= color('PATH', BOLD) %>.
65
65
 
66
66
  All parameters are optional. A live key or test key, or both is required, as well
67
67
  as at least one domain. Specify <%= color('--live-key', BOLD) %>, <%= color('--test-key', BOLD) %> or both and <%= color('--app-link-subdomain', BOLD) %>,
@@ -82,6 +82,7 @@ EOF
82
82
  c.option "--target MyAppTarget", String, "Name of a target to modify in the Xcode project"
83
83
  c.option "--podfile /path/to/Podfile", String, "Path to the Podfile for the project"
84
84
  c.option "--cartfile /path/to/Cartfile", String, "Path to the Cartfile for the project"
85
+ c.option "--carthage-command <command>", String, "Command to run when installing from Carthage (default: update --platform ios)"
85
86
  c.option "--frameworks AdSupport,CoreSpotlight,SafariServices", Array, "Comma-separated list of system frameworks to add to the project"
86
87
 
87
88
  c.option "--[no-]pod-repo-update", "Update the local podspec repo before installing (default: yes)"
@@ -95,6 +96,7 @@ EOF
95
96
  c.example "Use both live and test keys", "branch_io setup -L key_live_xxxx -T key_test_yyyy -D myapp.app.link"
96
97
  c.example "Use custom or non-Branch domains", "branch_io setup -D myapp.app.link,example.com,www.example.com"
97
98
  c.example "Avoid pod repo update", "branch_io setup --no-pod-repo-update"
99
+ c.example "Install using carthage bootstrap", "branch_io --carthage-command \"bootstrap --no-use-binaries\""
98
100
 
99
101
  c.action do |args, options|
100
102
  options.default(
@@ -104,7 +106,8 @@ EOF
104
106
  force: false,
105
107
  add_sdk: true,
106
108
  patch_source: true,
107
- commit: false
109
+ commit: false,
110
+ carthage_command: "update --platform ios"
108
111
  )
109
112
  Commands::SetupCommand.new(options).run!
110
113
  end
@@ -1,3 +1,5 @@
1
+ require "cocoapods-core"
2
+
1
3
  module BranchIOCLI
2
4
  module Commands
3
5
  class ReportCommand < Command
@@ -19,6 +21,10 @@ module BranchIOCLI
19
21
  # TODO: Write out command-line options or configuration from helper
20
22
  report.write "#{report_header}\n"
21
23
 
24
+ show_build_settings_cmd = "#{base_xcodebuild_cmd} -showBuildSettings"
25
+ report.write "$ #{show_build_settings_cmd}\n\n"
26
+ report.write `#{show_build_settings_cmd}`
27
+
22
28
  if config_helper.clean
23
29
  say "Cleaning"
24
30
  clean_cmd = "#{base_xcodebuild_cmd} clean"
@@ -37,33 +43,111 @@ module BranchIOCLI
37
43
  end
38
44
 
39
45
  def base_xcodebuild_cmd
40
- cmd = "xcodebuild"
46
+ cmd = "xcodebuild -sdk iphonesimulator"
41
47
  cmd = "#{cmd} -scheme #{config_helper.scheme}" if config_helper.scheme
42
48
  cmd = "#{cmd} -workspace #{config_helper.workspace_path}" if config_helper.workspace_path
43
- cmd = "#{cmd} -project #{config_helper.xcodeproj_path}" if config_helper.xcodeproj_path
49
+ cmd = "#{cmd} -project #{config_helper.xcodeproj_path}" if config_helper.xcodeproj_path && !config_helper.workspace_path
44
50
  cmd = "#{cmd} -target #{config_helper.target}" if config_helper.target
45
51
  cmd = "#{cmd} -configuration #{config_helper.configuration}" if config_helper.configuration
46
52
  cmd
47
53
  end
48
54
 
49
55
  def branch_version
50
- if config_helper.podfile_path && File.exist?("#{config_helper.podfile_path}.lock")
51
- podfile_lock = File.read "#{config_helper.podfile_path}.lock"
52
- matches = %r{Branch/Core \(= (\d+\.\d+\.\d+)\)}m.match podfile_lock
53
- return matches[1] if matches
54
- elsif config_helper.cartfile_path && File.exist?("#{config_helper.cartfile_path}.resolved")
55
- cartfile_resolved = File.read "#{config_helper.cartfile_path}.resolved"
56
- matches = /ios-branch-deep-linking" "(\d+\.\d+\.\d+)"/m.match cartfile_resolved
57
- return matches[1] if matches
58
- end
59
- nil
56
+ version_from_podfile_lock ||
57
+ version_from_cartfile_resolved ||
58
+ version_from_branch_framework ||
59
+ version_from_bnc_config_m
60
+ end
61
+
62
+ def requirement_from_podfile
63
+ return nil unless config_helper.podfile_path
64
+ podfile = File.read config_helper.podfile_path
65
+ matches = /\n?\s*pod\s+("Branch"|'Branch').*?\n/m.match podfile
66
+ matches ? matches[0].strip : nil
67
+ end
68
+
69
+ def requirement_from_cartfile
70
+ return nil unless config_helper.cartfile_path
71
+ cartfile = File.read config_helper.cartfile_path
72
+ matches = %r{\n?[^\n]+?BranchMetrics/(ios-branch-deep-linking|iOS-Deferred-Deep-Linking-SDK.*?).*?\n}m.match cartfile
73
+ matches ? matches[0].strip : nil
74
+ end
75
+
76
+ def version_from_podfile_lock
77
+ return nil unless config_helper.podfile_path && File.exist?("#{config_helper.podfile_path}.lock")
78
+ podfile_lock = Pod::Lockfile.from_file Pathname.new "#{config_helper.podfile_path}.lock"
79
+ version = podfile_lock.version "Branch"
80
+
81
+ version ? "#{version} [Podfile.lock]" : nil
82
+ end
83
+
84
+ def version_from_cartfile_resolved
85
+ return nil unless config_helper.cartfile_path && File.exist?("#{config_helper.cartfile_path}.resolved")
86
+ cartfile_resolved = File.read "#{config_helper.cartfile_path}.resolved"
87
+
88
+ # Matches:
89
+ # git "https://github.com/BranchMetrics/ios-branch-deep-linking"
90
+ # git "https://github.com/BranchMetrics/ios-branch-deep-linking/"
91
+ # git "https://github.com/BranchMetrics/iOS-Deferred-Deep-Linking-SDK"
92
+ # git "https://github.com/BranchMetrics/iOS-Deferred-Deep-Linking-SDK/"
93
+ # github "BranchMetrics/ios-branch-deep-linking"
94
+ # github "BranchMetrics/ios-branch-deep-linking/"
95
+ # github "BranchMetrics/iOS-Deferred-Deep-Linking-SDK"
96
+ # github "BranchMetrics/iOS-Deferred-Deep-Linking-SDK/"
97
+ matches = %r{(ios-branch-deep-linking|iOS-Deferred-Deep-Linking-SDK)/?" "(\d+\.\d+\.\d+)"}m.match cartfile_resolved
98
+ return nil unless matches
99
+ version = matches[2]
100
+ "#{version} [Cartfile.resolved]"
101
+ end
102
+
103
+ def version_from_branch_framework
104
+ framework = config_helper.xcodeproj.frameworks_group.files.find { |f| f.path =~ /Branch.framework$/ }
105
+ return nil unless framework
106
+ framework_path = framework.real_path
107
+ info_plist_path = File.join framework_path.to_s, "Info.plist"
108
+ return nil unless File.exist? info_plist_path
109
+
110
+ require "cfpropertylist"
111
+
112
+ raw_info_plist = CFPropertyList::List.new file: info_plist_path
113
+ info_plist = CFPropertyList.native_types raw_info_plist.value
114
+ version = info_plist["CFBundleVersion"]
115
+ version ? "#{version} [Branch.framework/Info.plist]" : nil
116
+ end
117
+
118
+ def version_from_bnc_config_m
119
+ # Look for BNCConfig.m in embedded source
120
+ bnc_config_m_ref = config_helper.xcodeproj.files.find { |f| f.path =~ /BNCConfig\.m$/ }
121
+ return nil unless bnc_config_m_ref
122
+ bnc_config_m = File.read bnc_config_m_ref.real_path
123
+ matches = /BNC_SDK_VERSION\s+=\s+@"(\d+\.\d+\.\d+)"/m.match bnc_config_m
124
+ return nil unless matches
125
+ version = matches[1]
126
+ "#{version} [BNCConfig.m]"
60
127
  end
61
128
 
62
129
  def report_header
63
130
  header = `xcodebuild -version`
131
+
132
+ if config_helper.podfile_path && File.exist?("#{config_helper.podfile_path}.lock")
133
+ podfile_lock = Pod::Lockfile.from_file Pathname.new "#{config_helper.podfile_path}.lock"
134
+ header = "#{header}\nUsing CocoaPods v. #{podfile_lock.cocoapods_version}\n"
135
+ end
136
+
137
+ podfile_requirement = requirement_from_podfile
138
+ header = "#{header}\nFrom Podfile:\n#{podfile_requirement}\n" if podfile_requirement
139
+
140
+ cartfile_requirement = requirement_from_cartfile
141
+ header = "#{header}\nFrom Cartfile:\n#{cartfile_requirement}\n" if cartfile_requirement
142
+
64
143
  version = branch_version
65
- header = "#{header}\nBranch SDK v. #{version}" if version
66
- "#{header}\n"
144
+ if version
145
+ header = "#{header}\nBranch SDK v. #{version}\n"
146
+ else
147
+ header = "Branch SDK not found.\n"
148
+ end
149
+
150
+ header
67
151
  end
68
152
  end
69
153
  end
@@ -29,11 +29,10 @@ module BranchIOCLI
29
29
  helper.add_direct options
30
30
  end
31
31
 
32
- target_name = options.target # may be nil
33
32
  is_app_target = !config_helper.target.extension_target_type?
34
33
 
35
34
  if is_app_target && options.validate &&
36
- !helper.validate_team_and_bundle_ids_from_aasa_files(xcodeproj, target_name, @domains)
35
+ !helper.validate_team_and_bundle_ids_from_aasa_files(@domains)
37
36
  say "Universal Link configuration failed validation."
38
37
  helper.errors.each { |error| say " #{error}" }
39
38
  return unless options.force
@@ -42,14 +41,14 @@ module BranchIOCLI
42
41
  end
43
42
 
44
43
  # the following calls can all raise IOError
45
- helper.add_keys_to_info_plist xcodeproj, target_name, @keys
46
- helper.add_branch_universal_link_domains_to_info_plist xcodeproj, target_name, @domains if is_app_target
44
+ helper.add_keys_to_info_plist @keys
45
+ helper.add_branch_universal_link_domains_to_info_plist @domains if is_app_target
47
46
  helper.ensure_uri_scheme_in_info_plist if is_app_target # does nothing if already present
48
47
 
49
- new_path = helper.add_universal_links_to_project xcodeproj, target_name, @domains, false if is_app_target
48
+ new_path = helper.add_universal_links_to_project @domains, false if is_app_target
50
49
  `git add #{new_path}` if options.commit && new_path
51
50
 
52
- helper.add_system_frameworks xcodeproj, target_name, options.frameworks unless options.frameworks.nil? || options.frameworks.empty?
51
+ config_helper.target.add_system_frameworks options.frameworks unless options.frameworks.nil? || options.frameworks.empty?
53
52
 
54
53
  xcodeproj.save
55
54
 
@@ -7,17 +7,10 @@ module BranchIOCLI
7
7
  end
8
8
 
9
9
  def run!
10
- # raises
11
- xcodeproj = config_helper.xcodeproj
12
-
13
10
  valid = true
14
11
 
15
12
  unless options.domains.nil? || options.domains.empty?
16
- domains_valid = helper.validate_project_domains(
17
- options.domains,
18
- xcodeproj,
19
- options.target
20
- )
13
+ domains_valid = helper.validate_project_domains(options.domains)
21
14
 
22
15
  if domains_valid
23
16
  say "Project domains match :domains parameter: ✅"
@@ -29,7 +22,7 @@ module BranchIOCLI
29
22
  valid &&= domains_valid
30
23
  end
31
24
 
32
- configuration_valid = helper.validate_team_and_bundle_ids_from_aasa_files xcodeproj, options.target
25
+ configuration_valid = helper.validate_team_and_bundle_ids_from_aasa_files
33
26
  unless configuration_valid
34
27
  say "Universal Link configuration failed validation."
35
28
  helper.errors.each { |error| say " #{error}" }
@@ -26,6 +26,7 @@ module BranchIOCLI
26
26
  attr_reader :all_domains
27
27
  attr_reader :podfile_path
28
28
  attr_reader :cartfile_path
29
+ attr_reader :carthage_command
29
30
  attr_reader :target
30
31
  attr_reader :uri_scheme
31
32
  attr_reader :pod_repo_update
@@ -72,9 +73,12 @@ module BranchIOCLI
72
73
 
73
74
  # If --podfile is present or a Podfile was found, don't look for a Cartfile.
74
75
  validate_buildfile_path options.cartfile, "Cartfile" if @sdk_integration_mode.nil? && options.add_sdk
76
+ @carthage_command = options.carthage_command if @sdk_integration_mode == :carthage
75
77
 
76
78
  validate_sdk_addition options
77
79
 
80
+ BranchHelper.verify_git if @commit
81
+
78
82
  print_setup_configuration
79
83
  end
80
84
 
@@ -133,6 +137,7 @@ EOF
133
137
  <%= color('URI scheme:', BOLD) %> #{@uri_scheme || '(none)'}
134
138
  <%= color('Podfile:', BOLD) %> #{@podfile_path || '(none)'}
135
139
  <%= color('Cartfile:', BOLD) %> #{@cartfile_path || '(none)'}
140
+ <%= color('Carthage command:', BOLD) %> #{@carthage_command || '(none)'}
136
141
  <%= color('Pod repo update:', BOLD) %> #{@pod_repo_update.inspect}
137
142
  <%= color('Validate:', BOLD) %> #{@validate.inspect}
138
143
  <%= color('Force:', BOLD) %> #{@force.inspect}
@@ -263,6 +268,12 @@ EOF
263
268
  path = options.xcodeproj
264
269
  @xcodeproj = Xcodeproj::Project.open options.xcodeproj
265
270
  @xcodeproj_path = options.xcodeproj
271
+ else
272
+ # Pass --workspace and --xcodeproj to override this inference.
273
+ if @workspace && @workspace.file_references.count > 0 && @workspace.file_references.first.path =~ /\.xcodeproj$/
274
+ @xcodeproj_path = File.expand_path "../#{@workspace.file_references.first.path}", @workspace_path
275
+ @xcodeproj = Xcodeproj::Project.open @xcodeproj_path
276
+ end
266
277
  end
267
278
  return if @workspace || @xcodeproj
268
279
  rescue StandardError => e
@@ -271,7 +282,7 @@ EOF
271
282
 
272
283
  # Try to find first a workspace, then a project
273
284
  all_workspace_paths = Dir[File.expand_path(File.join(".", "**/*.xcworkspace"))]
274
- .reject { |w| w =~ %r{/project.pbxproj$} }
285
+ .reject { |w| w =~ %r{/project.xcworkspace$} }
275
286
  .select do |p|
276
287
  valid = true
277
288
  Pathname.new(p).each_filename do |f|
@@ -302,6 +313,13 @@ EOF
302
313
  if path =~ /\.xcworkspace$/
303
314
  @workspace = Xcodeproj::Workspace.new_from_xcworkspace path
304
315
  @workspace_path = path
316
+
317
+ # Pass --workspace and --xcodeproj to override this inference.
318
+ if @workspace.file_references.count > 0 && @workspace.file_references.first.path =~ /\.xcodeproj$/
319
+ @xcodeproj_path = File.expand_path "../#{@workspace.file_references.first.path}", @workspace_path
320
+ @xcodeproj = Xcodeproj::Project.open @xcodeproj_path
321
+ end
322
+
305
323
  return
306
324
  elsif path =~ /\.xcodeproj$/
307
325
  @xcodeproj = Xcodeproj::Project.open path
@@ -491,6 +509,7 @@ EOF
491
509
  @podfile_path = File.expand_path "../Podfile", @xcodeproj_path
492
510
  when :carthage
493
511
  @cartfile_path = File.expand_path "../Cartfile", @xcodeproj_path
512
+ @carthage_command = options.carthage_command
494
513
  end
495
514
  end
496
515
  end
@@ -16,25 +16,46 @@ module BranchIOCLI
16
16
  PRODUCT_BUNDLE_IDENTIFIER = "PRODUCT_BUNDLE_IDENTIFIER"
17
17
  RELEASE_CONFIGURATION = "Release"
18
18
 
19
- def add_keys_to_info_plist(project, target_name, keys, configuration = RELEASE_CONFIGURATION)
20
- update_info_plist_setting project, target_name, configuration do |info_plist|
21
- # add/overwrite Branch key(s)
22
- if keys.count > 1
23
- info_plist["branch_key"] = keys
24
- elsif keys[:live]
25
- info_plist["branch_key"] = keys[:live]
26
- else # no need to validate here, which was done by the action
27
- info_plist["branch_key"] = keys[:test]
19
+ def has_multiple_info_plists?
20
+ ConfigurationHelper.xcodeproj.build_configurations.inject([]) do |files, config|
21
+ files + [expanded_build_setting(ConfigurationHelper.target, "INFOPLIST_FILE", config.name)]
22
+ end.uniq.count > 1
23
+ end
24
+
25
+ def add_keys_to_info_plist(keys)
26
+ if has_multiple_info_plists?
27
+ ConfigurationHelper.xcodeproj.build_configurations.each do |config|
28
+ update_info_plist_setting config.name do |info_plist|
29
+ if keys.count > 1
30
+ # Use test key in debug configs and live key in release configs
31
+ info_plist["branch_key"] = config.debug? ? keys[:test] : keys[:live]
32
+ else
33
+ info_plist["branch_key"] = keys[:live] ? keys[:live] : keys[:test]
34
+ end
35
+ end
36
+ end
37
+ else
38
+ update_info_plist_setting RELEASE_CONFIGURATION do |info_plist|
39
+ # add/overwrite Branch key(s)
40
+ if keys.count > 1
41
+ info_plist["branch_key"] = keys
42
+ elsif keys[:live]
43
+ info_plist["branch_key"] = keys[:live]
44
+ else
45
+ info_plist["branch_key"] = keys[:test]
46
+ end
28
47
  end
29
48
  end
30
49
  end
31
50
 
32
- def add_branch_universal_link_domains_to_info_plist(project, target_name, domains, configuration = RELEASE_CONFIGURATION)
51
+ def add_branch_universal_link_domains_to_info_plist(domains)
33
52
  # Add all supplied domains unless all are app.link domains.
34
53
  return if domains.all? { |d| d =~ /app\.link$/ }
35
54
 
36
- update_info_plist_setting project, target_name, configuration do |info_plist|
37
- info_plist["branch_universal_link_domains"] = domains
55
+ ConfigurationHelper.xcodeproj.build_configurations.each do |config|
56
+ update_info_plist_setting config.name do |info_plist|
57
+ info_plist["branch_universal_link_domains"] = domains
58
+ end
38
59
  end
39
60
  end
40
61
 
@@ -44,47 +65,33 @@ module BranchIOCLI
44
65
  # No URI scheme specified. Do nothing.
45
66
  return if uri_scheme.nil?
46
67
 
47
- update_info_plist_setting ConfigurationHelper.xcodeproj,
48
- ConfigurationHelper.target.name,
49
- RELEASE_CONFIGURATION do |info_plist|
50
- url_types = info_plist["CFBundleURLTypes"] || []
51
- uri_schemes = url_types.inject([]) { |schemes, t| schemes + t["CFBundleURLSchemes"] }
52
-
53
- if uri_schemes.empty?
54
- say "No URI scheme currently defined in project."
55
- else
56
- say "Existing URI schemes found in project:"
57
- uri_schemes.each do |scheme|
58
- say " #{scheme}"
59
- end
68
+ ConfigurationHelper.xcodeproj.build_configurations.each do |config|
69
+ update_info_plist_setting config.name do |info_plist|
70
+ url_types = info_plist["CFBundleURLTypes"] || []
71
+ uri_schemes = url_types.inject([]) { |schemes, t| schemes + t["CFBundleURLSchemes"] }
72
+
73
+ # Already present. Don't mess with the identifier.
74
+ next if uri_schemes.include? uri_scheme
75
+
76
+ # Not found. Add. Don't worry about the CFBundleURLName (reverse-DNS identifier)
77
+ # TODO: Should we prompt here to add or let them change the Dashboard? If there's already
78
+ # a URI scheme in the app, seems likely they'd want to use it. They may have just made
79
+ # a typo at the CLI or in the Dashboard.
80
+ url_types << {
81
+ "CFBundleURLSchemes" => [uri_scheme]
82
+ }
83
+ info_plist["CFBundleURLTypes"] = url_types
60
84
  end
61
-
62
- # Already present. Don't mess with the identifier.
63
- return if uri_schemes.include? uri_scheme
64
-
65
- # Not found. Add. Don't worry about the CFBundleURLName (reverse-DNS identifier)
66
- # TODO: Should we prompt here to add or let them change the Dashboard? If there's already
67
- # a URI scheme in the app, seems likely they'd want to use it. They may have just made
68
- # a typo at the CLI or in the Dashboard.
69
- url_types << {
70
- "CFBundleURLSchemes" => [uri_scheme]
71
- }
72
- info_plist["CFBundleURLTypes"] = url_types
73
-
74
- say "Added URI scheme #{uri_scheme} to project."
75
85
  end
76
86
  end
77
87
 
78
- def update_info_plist_setting(project, target_name, configuration = RELEASE_CONFIGURATION, &b)
79
- # raises
80
- target = target_from_project project, target_name
81
-
88
+ def update_info_plist_setting(configuration = RELEASE_CONFIGURATION, &b)
82
89
  # find the Info.plist paths for this configuration
83
- info_plist_path = expanded_build_setting target, "INFOPLIST_FILE", configuration
90
+ info_plist_path = expanded_build_setting ConfigurationHelper.target, "INFOPLIST_FILE", configuration
84
91
 
85
92
  raise "Info.plist not found for configuration #{configuration}" if info_plist_path.nil?
86
93
 
87
- project_parent = File.dirname project.path
94
+ project_parent = File.dirname ConfigurationHelper.xcodeproj_path
88
95
 
89
96
  info_plist_path = File.expand_path info_plist_path, project_parent
90
97
 
@@ -98,9 +105,9 @@ module BranchIOCLI
98
105
  add_change info_plist_path
99
106
  end
100
107
 
101
- def add_universal_links_to_project(project, target_name, domains, remove_existing, configuration = RELEASE_CONFIGURATION)
102
- # raises
103
- target = target_from_project project, target_name
108
+ def add_universal_links_to_project(domains, remove_existing, configuration = RELEASE_CONFIGURATION)
109
+ project = ConfigurationHelper.xcodeproj
110
+ target = ConfigurationHelper.target
104
111
 
105
112
  relative_entitlements_path = expanded_build_setting target, CODE_SIGN_ENTITLEMENTS, configuration
106
113
  project_parent = File.dirname project.path
@@ -150,7 +157,7 @@ module BranchIOCLI
150
157
  [team, bundle]
151
158
  end
152
159
 
153
- def update_team_and_bundle_ids_from_aasa_file(project, target_name, domain)
160
+ def update_team_and_bundle_ids_from_aasa_file(domain)
154
161
  # raises
155
162
  identifiers = app_ids_from_aasa_file domain
156
163
  raise "Multiple appIDs found in AASA file" if identifiers.count > 1
@@ -158,11 +165,11 @@ module BranchIOCLI
158
165
  identifier = identifiers[0]
159
166
  team, bundle = team_and_bundle_from_app_id identifier
160
167
 
161
- update_team_and_bundle_ids project, target_name, team, bundle
162
- add_change project.path.expand_path
168
+ update_team_and_bundle_ids team, bundle
169
+ add_change ConfigurationHelper.xcodeproj_path
163
170
  end
164
171
 
165
- def validate_team_and_bundle_ids_from_aasa_files(project, target_name, domains = [], remove_existing = false, configuration = RELEASE_CONFIGURATION)
172
+ def validate_team_and_bundle_ids_from_aasa_files(domains = [], remove_existing = false, configuration = RELEASE_CONFIGURATION)
166
173
  @errors = []
167
174
  valid = true
168
175
 
@@ -172,7 +179,7 @@ module BranchIOCLI
172
179
  # Don't validate domains to be removed (#16)
173
180
  all_domains = domains
174
181
  else
175
- all_domains = (domains + domains_from_project(project, target_name, configuration)).uniq
182
+ all_domains = (domains + domains_from_project(configuration)).uniq
176
183
  end
177
184
 
178
185
  if all_domains.empty?
@@ -184,7 +191,7 @@ module BranchIOCLI
184
191
  end
185
192
 
186
193
  all_domains.each do |domain|
187
- domain_valid = validate_team_and_bundle_ids project, target_name, domain, configuration
194
+ domain_valid = validate_team_and_bundle_ids domain, configuration
188
195
  valid &&= domain_valid
189
196
  say "Valid Universal Link configuration for #{domain} ✅" if domain_valid
190
197
  end
@@ -272,9 +279,8 @@ module BranchIOCLI
272
279
  nil
273
280
  end
274
281
 
275
- def validate_team_and_bundle_ids(project, target_name, domain, configuration)
276
- # raises
277
- target = target_from_project project, target_name
282
+ def validate_team_and_bundle_ids(domain, configuration)
283
+ target = ConfigurationHelper.target
278
284
 
279
285
  product_bundle_identifier = expanded_build_setting target, PRODUCT_BUNDLE_IDENTIFIER, configuration
280
286
  development_team = expanded_build_setting target, DEVELOPMENT_TEAM, configuration
@@ -292,9 +298,9 @@ module BranchIOCLI
292
298
  match_found
293
299
  end
294
300
 
295
- def validate_project_domains(expected, project, target, configuration = RELEASE_CONFIGURATION)
301
+ def validate_project_domains(expected, configuration = RELEASE_CONFIGURATION)
296
302
  @errors = []
297
- project_domains = domains_from_project project, target, configuration
303
+ project_domains = domains_from_project configuration
298
304
  valid = expected.count == project_domains.count
299
305
  if valid
300
306
  sorted = expected.sort
@@ -312,9 +318,8 @@ module BranchIOCLI
312
318
  valid
313
319
  end
314
320
 
315
- def update_team_and_bundle_ids(project, target_name, team, bundle)
316
- # raises
317
- target = target_from_project project, target_name
321
+ def update_team_and_bundle_ids(team, bundle)
322
+ target = ConfigurationHelper.target
318
323
 
319
324
  target.build_configuration_list.set_setting PRODUCT_BUNDLE_IDENTIFIER, bundle
320
325
  target.build_configuration_list.set_setting DEVELOPMENT_TEAM, team
@@ -338,9 +343,9 @@ module BranchIOCLI
338
343
  target
339
344
  end
340
345
 
341
- def domains_from_project(project, target_name, configuration = RELEASE_CONFIGURATION)
342
- # Raises. Does not return nil.
343
- target = target_from_project project, target_name
346
+ def domains_from_project(configuration = RELEASE_CONFIGURATION)
347
+ project = ConfigurationHelper.xcodeproj
348
+ target = ConfigurationHelper.target
344
349
 
345
350
  relative_entitlements_path = expanded_build_setting target, CODE_SIGN_ENTITLEMENTS, configuration
346
351
  return [] if relative_entitlements_path.nil?
@@ -373,12 +378,6 @@ module BranchIOCLI
373
378
  setting_value
374
379
  end
375
380
 
376
- def add_system_frameworks(project, target_name, frameworks)
377
- target = target_from_project project, target_name
378
-
379
- target.add_system_framework frameworks
380
- end
381
-
382
381
  def patch_app_delegate_swift(project)
383
382
  app_delegate_swift = project.files.find { |f| f.path =~ /AppDelegate.swift$/ }
384
383
  return false if app_delegate_swift.nil?
@@ -397,14 +396,53 @@ module BranchIOCLI
397
396
  mode: :prepend
398
397
  )
399
398
 
400
- init_session_text = ConfigurationHelper.keys.count <= 1 ? "" : <<EOF
399
+ patch_did_finish_launching_method_swift app_delegate_swift_path
400
+ patch_continue_user_activity_method_swift app_delegate_swift_path
401
+ patch_open_url_method_swift app_delegate_swift_path
402
+
403
+ add_change app_delegate_swift_path
404
+ true
405
+ end
406
+
407
+ def patch_app_delegate_objc(project)
408
+ app_delegate_objc = project.files.find { |f| f.path =~ /AppDelegate.m$/ }
409
+ return false if app_delegate_objc.nil?
410
+
411
+ app_delegate_objc_path = app_delegate_objc.real_path.to_s
412
+
413
+ app_delegate = File.read app_delegate_objc_path
414
+ return false if app_delegate =~ %r{^\s+#import\s+<Branch/Branch.h>|^\s+@import\s+Branch;}
415
+
416
+ say "Patching #{app_delegate_objc_path}"
417
+
418
+ apply_patch(
419
+ files: app_delegate_objc_path,
420
+ regexp: /^\s+@import|^\s+#import.*$/,
421
+ text: "\n#import <Branch/Branch.h>",
422
+ mode: :prepend
423
+ )
424
+
425
+ patch_did_finish_launching_method_objc app_delegate_objc_path
426
+ patch_continue_user_activity_method_objc app_delegate_objc_path
427
+ patch_open_url_method_objc app_delegate_objc_path
428
+
429
+ add_change app_delegate_objc_path
430
+ true
431
+ end
432
+
433
+ def patch_did_finish_launching_method_swift(app_delegate_swift_path)
434
+ app_delegate_swift = File.read app_delegate_swift_path
435
+
436
+ if app_delegate_swift =~ /didFinishLaunching[^\n]+?\{/m
437
+ # method already present
438
+ init_session_text = ConfigurationHelper.keys.count <= 1 || has_multiple_info_plists? ? "" : <<EOF
401
439
  #if DEBUG
402
440
  Branch.setUseTestBranchKey(true)
403
441
  #endif
404
442
 
405
443
  EOF
406
444
 
407
- init_session_text += <<-EOF
445
+ init_session_text += <<-EOF
408
446
  Branch.getInstance().initSession(launchOptions: launchOptions) {
409
447
  universalObject, linkProperties, error in
410
448
 
@@ -412,130 +450,105 @@ EOF
412
450
  }
413
451
  EOF
414
452
 
415
- apply_patch(
416
- files: app_delegate_swift_path,
417
- regexp: /didFinishLaunchingWithOptions.*?\{[^\n]*\n/m,
418
- text: init_session_text,
419
- mode: :append
420
- )
421
-
422
- if app_delegate =~ /application:.*continue userActivity:.*restorationHandler:/
423
- # Add something to the top of the method
424
- continue_user_activity_text = <<-EOF
425
- // TODO: Adjust your method as you see fit.
426
- if Branch.getInstance.continue(userActivity) {
427
- return true
428
- }
429
-
430
- EOF
431
-
432
453
  apply_patch(
433
454
  files: app_delegate_swift_path,
434
- regexp: /application:.*continue userActivity:.*restorationHandler:.*?\{.*?\n/m,
435
- text: continue_user_activity_text,
455
+ regexp: /didFinishLaunchingWithOptions.*?\{[^\n]*\n/m,
456
+ text: init_session_text,
436
457
  mode: :append
437
458
  )
438
459
  else
439
- # Add the application:continueUserActivity:restorationHandler method if it does not exist
440
- continue_user_activity_text = <<-EOF
460
+ # method not present. add entire method
441
461
 
462
+ method_text = <<EOF
442
463
 
443
- func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
444
- return Branch.getInstance().continue(userActivity)
464
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
465
+ EOF
466
+
467
+ if ConfigurationHelper.keys.count > 1 && !has_multiple_info_plists?
468
+ method_text += <<EOF
469
+ #if DEBUG
470
+ Branch.setUseTestBranchKey(true)
471
+ #endif
472
+
473
+ EOF
474
+ end
475
+
476
+ method_text += <<-EOF
477
+ Branch.getInstance().initSession(launchOptions: launchOptions) {
478
+ universalObject, linkProperties, error in
479
+
480
+ // TODO: Route Branch links
481
+ }
482
+ return true
445
483
  }
446
- EOF
484
+ EOF
447
485
 
448
486
  apply_patch(
449
487
  files: app_delegate_swift_path,
450
- regexp: /\n\s*\}[^{}]*\Z/m,
451
- text: continue_user_activity_text,
452
- mode: :prepend
488
+ regexp: /var\s+window\s?:\s?UIWindow\?.*?\n/m,
489
+ text: method_text,
490
+ mode: :append
453
491
  )
454
492
  end
455
-
456
- patch_open_url_method_swift app_delegate_swift_path
457
-
458
- add_change app_delegate_swift_path
459
- true
460
493
  end
461
494
 
462
- def patch_app_delegate_objc(project)
463
- app_delegate_objc = project.files.find { |f| f.path =~ /AppDelegate.m$/ }
464
- return false if app_delegate_objc.nil?
465
-
466
- app_delegate_objc_path = app_delegate_objc.real_path.to_s
467
-
468
- app_delegate = File.read app_delegate_objc_path
469
- return false if app_delegate =~ %r{^\s+#import\s+<Branch/Branch.h>|^\s+@import\s+Branch;}
470
-
471
- say "Patching #{app_delegate_objc_path}"
472
-
473
- apply_patch(
474
- files: app_delegate_objc_path,
475
- regexp: /^\s+@import|^\s+#import.*$/,
476
- text: "\n#import <Branch/Branch.h>",
477
- mode: :prepend
478
- )
495
+ def patch_did_finish_launching_method_objc(app_delegate_objc_path)
496
+ app_delegate_objc = File.read app_delegate_objc_path
479
497
 
480
- init_session_text = ConfigurationHelper.keys.count <= 1 ? "" : <<EOF
498
+ if app_delegate_objc =~ /didFinishLaunchingWithOptions/m
499
+ # method exists. patch it.
500
+ init_session_text = ConfigurationHelper.keys.count <= 1 || has_multiple_info_plists? ? "" : <<EOF
481
501
  #ifdef DEBUG
482
502
  [Branch setUseTestBranchKey:YES];
483
503
  #endif // DEBUG
484
504
 
485
505
  EOF
486
506
 
487
- init_session_text += <<-EOF
507
+ init_session_text += <<-EOF
488
508
  [[Branch getInstance] initSessionWithLaunchOptions:launchOptions
489
509
  andRegisterDeepLinkHandlerUsingBranchUniversalObject:^(BranchUniversalObject *universalObject, BranchLinkProperties *linkProperties, NSError *error){
490
510
  // TODO: Route Branch links
491
511
  }];
492
- EOF
493
-
494
- apply_patch(
495
- files: app_delegate_objc_path,
496
- regexp: /didFinishLaunchingWithOptions.*?\{[^\n]*\n/m,
497
- text: init_session_text,
498
- mode: :append
499
- )
500
-
501
- if app_delegate =~ /application:.*continueUserActivity:.*restorationHandler:/
502
- continue_user_activity_text = <<-EOF
503
- // TODO: Adjust your method as you see fit.
504
- if ([[Branch getInstance] continueUserActivity:userActivity]) {
505
- return YES;
506
- }
507
-
508
- EOF
512
+ EOF
509
513
 
510
514
  apply_patch(
511
515
  files: app_delegate_objc_path,
512
- regexp: /application:.*continueUserActivity:.*restorationHandler:.*?\{.*?\n/m,
513
- text: continue_user_activity_text,
516
+ regexp: /didFinishLaunchingWithOptions.*?\{[^\n]*\n/m,
517
+ text: init_session_text,
514
518
  mode: :append
515
519
  )
516
520
  else
517
- # Add the application:continueUserActivity:restorationHandler method if it does not exist
518
- continue_user_activity_text = <<-EOF
521
+ # method does not exist. add it.
522
+ method_text = <<EOF
519
523
 
524
+ - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
525
+ EOF
520
526
 
521
- - (BOOL)application:(UIApplication *)app continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * _Nullable))restorationHandler
522
- {
523
- return [[Branch getInstance] continueUserActivity:userActivity];
527
+ if ConfigurationHelper.keys.count > 1 && !has_multiple_info_plists?
528
+ method_text += <<EOF
529
+ #ifdef DEBUG
530
+ [Branch setUseTestBranchKey:YES];
531
+ #endif // DEBUG
532
+
533
+ EOF
534
+ end
535
+
536
+ method_text += <<-EOF
537
+ [[Branch getInstance] initSessionWithLaunchOptions:launchOptions
538
+ andRegisterDeepLinkHandlerUsingBranchUniversalObject:^(BranchUniversalObject *universalObject, BranchLinkProperties *linkProperties, NSError *error){
539
+ // TODO: Route Branch links
540
+ }];
541
+ return YES;
524
542
  }
525
543
  EOF
526
544
 
527
545
  apply_patch(
528
546
  files: app_delegate_objc_path,
529
- regexp: /\n\s*@end[^@]*\Z/m,
530
- text: continue_user_activity_text,
531
- mode: :prepend
547
+ regexp: /^@implementation.*?\n/m,
548
+ text: method_text,
549
+ mode: :append
532
550
  )
533
551
  end
534
-
535
- patch_open_url_method_objc app_delegate_objc_path
536
-
537
- add_change app_delegate_objc_path
538
- true
539
552
  end
540
553
 
541
554
  def patch_open_url_method_swift(app_delegate_swift_path)
@@ -592,6 +605,43 @@ EOF
592
605
  end
593
606
  end
594
607
 
608
+ def patch_continue_user_activity_method_swift(app_delegate_swift_path)
609
+ app_delegate = File.read app_delegate_swift_path
610
+ if app_delegate =~ /application:.*continue userActivity:.*restorationHandler:/
611
+ # Add something to the top of the method
612
+ continue_user_activity_text = <<-EOF
613
+ // TODO: Adjust your method as you see fit.
614
+ if Branch.getInstance.continue(userActivity) {
615
+ return true
616
+ }
617
+
618
+ EOF
619
+
620
+ apply_patch(
621
+ files: app_delegate_swift_path,
622
+ regexp: /application:.*continue userActivity:.*restorationHandler:.*?\{.*?\n/m,
623
+ text: continue_user_activity_text,
624
+ mode: :append
625
+ )
626
+ else
627
+ # Add the application:continueUserActivity:restorationHandler method if it does not exist
628
+ continue_user_activity_text = <<-EOF
629
+
630
+
631
+ func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([Any]?) -> Void) -> Bool {
632
+ return Branch.getInstance().continue(userActivity)
633
+ }
634
+ EOF
635
+
636
+ apply_patch(
637
+ files: app_delegate_swift_path,
638
+ regexp: /\n\s*\}[^{}]*\Z/m,
639
+ text: continue_user_activity_text,
640
+ mode: :prepend
641
+ )
642
+ end
643
+ end
644
+
595
645
  def patch_open_url_method_objc(app_delegate_objc_path)
596
646
  app_delegate_objc = File.read app_delegate_objc_path
597
647
  if app_delegate_objc =~ /application:.*openURL:.*options/
@@ -646,21 +696,69 @@ EOF
646
696
  end
647
697
  end
648
698
 
699
+ def patch_continue_user_activity_method_objc(app_delegate_objc_path)
700
+ app_delegate = File.read app_delegate_objc_path
701
+ if app_delegate =~ /application:.*continueUserActivity:.*restorationHandler:/
702
+ continue_user_activity_text = <<-EOF
703
+ // TODO: Adjust your method as you see fit.
704
+ if ([[Branch getInstance] continueUserActivity:userActivity]) {
705
+ return YES;
706
+ }
707
+
708
+ EOF
709
+
710
+ apply_patch(
711
+ files: app_delegate_objc_path,
712
+ regexp: /application:.*continueUserActivity:.*restorationHandler:.*?\{.*?\n/m,
713
+ text: continue_user_activity_text,
714
+ mode: :append
715
+ )
716
+ else
717
+ # Add the application:continueUserActivity:restorationHandler method if it does not exist
718
+ continue_user_activity_text = <<-EOF
719
+
720
+
721
+ - (BOOL)application:(UIApplication *)app continueUserActivity:(nonnull NSUserActivity *)userActivity restorationHandler:(nonnull void (^)(NSArray * _Nullable))restorationHandler
722
+ {
723
+ return [[Branch getInstance] continueUserActivity:userActivity];
724
+ }
725
+ EOF
726
+
727
+ apply_patch(
728
+ files: app_delegate_objc_path,
729
+ regexp: /\n\s*@end[^@]*\Z/m,
730
+ text: continue_user_activity_text,
731
+ mode: :prepend
732
+ )
733
+ end
734
+ end
735
+
649
736
  def patch_podfile(podfile_path)
650
737
  podfile = File.read podfile_path
651
738
 
652
739
  # Podfile already contains the Branch pod
740
+ # TODO: Allow for adding to multiple targets in the Podfile
653
741
  return false if podfile =~ /pod\s+('Branch'|"Branch")/
654
742
 
655
743
  say "Adding pod \"Branch\" to #{podfile_path}"
656
744
 
657
- # TODO: Improve this patch. Should work in the majority of cases for now.
658
- apply_patch(
659
- files: podfile_path,
660
- regexp: /^(\s*)pod\s*/,
661
- text: "\n\\1pod \"Branch\"\n",
662
- mode: :prepend
663
- )
745
+ if podfile =~ /target\s+(["'])#{ConfigurationHelper.target.name}\1\s+do.*?\n/m
746
+ # if there is a target block for this target:
747
+ apply_patch(
748
+ files: podfile_path,
749
+ regexp: /\n(\s*)target\s+(["'])#{ConfigurationHelper.target.name}\2\s+do.*?\n/m,
750
+ text: "\\1 pod \"Branch\"\n",
751
+ mode: :append
752
+ )
753
+ else
754
+ # add to the abstract_target for this target
755
+ apply_patch(
756
+ files: podfile_path,
757
+ regexp: /^(\s*)target\s+["']#{ConfigurationHelper.target.name}/,
758
+ text: "\\1pod \"Branch\"\n",
759
+ mode: :prepend
760
+ )
761
+ end
664
762
 
665
763
  true
666
764
  end
@@ -684,12 +782,14 @@ EOF
684
782
  end
685
783
 
686
784
  def add_cocoapods(options)
785
+ verify_cocoapods
786
+
687
787
  podfile_path = ConfigurationHelper.podfile_path
688
788
 
689
789
  install_command = "pod install"
690
790
  install_command += " --repo-update" if options.pod_repo_update
691
791
  Dir.chdir(File.dirname(podfile_path)) do
692
- system "pod init"
792
+ system_command "pod init"
693
793
  apply_patch(
694
794
  files: podfile_path,
695
795
  regexp: /^(\s*)# Pods for #{ConfigurationHelper.target.name}$/,
@@ -697,7 +797,7 @@ EOF
697
797
  text: "\n\\1pod \"Branch\"",
698
798
  global: false
699
799
  )
700
- system install_command
800
+ system_command install_command
701
801
  end
702
802
 
703
803
  add_change podfile_path
@@ -714,6 +814,7 @@ EOF
714
814
 
715
815
  def add_carthage(options)
716
816
  # TODO: Collapse this and Command::update_cartfile
817
+ verify_carthage
717
818
 
718
819
  # 1. Generate Cartfile
719
820
  cartfile_path = ConfigurationHelper.cartfile_path
@@ -725,7 +826,7 @@ EOF
725
826
 
726
827
  # 2. carthage update
727
828
  Dir.chdir(File.dirname(cartfile_path)) do
728
- system "carthage update --platform ios"
829
+ system_command "carthage #{ConfigurationHelper.carthage_command}"
729
830
  end
730
831
 
731
832
  # 3. Add Cartfile and Cartfile.resolved to commit (in case :commit param specified)
@@ -797,7 +898,7 @@ EOF
797
898
 
798
899
  # Now the current framework is in framework_path
799
900
 
800
- say "Adding to #{@xcodeproj_path}"
901
+ say "Adding to #{ConfigurationHelper.xcodeproj_path}"
801
902
 
802
903
  # Add as a dependency in the Frameworks group
803
904
  framework = frameworks_group.new_file "Branch.framework" # relative to frameworks_group.real_path
@@ -824,6 +925,8 @@ EOF
824
925
  end
825
926
 
826
927
  def update_podfile(options)
928
+ verify_cocoapods
929
+
827
930
  podfile_path = ConfigurationHelper.podfile_path
828
931
  return false if podfile_path.nil?
829
932
 
@@ -836,7 +939,7 @@ EOF
836
939
  command += ' --repo-update' if options.pod_repo_update
837
940
 
838
941
  Dir.chdir(File.dirname(podfile_path)) do
839
- system command
942
+ system_command command
840
943
  end
841
944
 
842
945
  # 3. Add Podfile and Podfile.lock to commit (in case :commit param specified)
@@ -856,6 +959,8 @@ EOF
856
959
  end
857
960
 
858
961
  def update_cartfile(options, project)
962
+ verify_carthage
963
+
859
964
  cartfile_path = ConfigurationHelper.cartfile_path
860
965
  return false if cartfile_path.nil?
861
966
 
@@ -864,7 +969,7 @@ EOF
864
969
 
865
970
  # 2. carthage update
866
971
  Dir.chdir(File.dirname(cartfile_path)) do
867
- system "carthage update --platform ios"
972
+ system_command "carthage #{ConfigurationHelper.carthage_command}"
868
973
  end
869
974
 
870
975
  # 3. Add Cartfile and Cartfile.resolved to commit (in case :commit param specified)
@@ -903,6 +1008,79 @@ EOF
903
1008
  def patch_source(xcodeproj)
904
1009
  patch_app_delegate_swift(xcodeproj) || patch_app_delegate_objc(xcodeproj)
905
1010
  end
1011
+
1012
+ def verify_cocoapods
1013
+ pod_cmd = `which pod`
1014
+ return unless pod_cmd.empty?
1015
+
1016
+ gem_cmd = `which gem`
1017
+ if gem_cmd.empty?
1018
+ say "'pod' command not available in PATH and 'gem' command not available in PATH to install cocoapods."
1019
+ exit(-1)
1020
+ end
1021
+
1022
+ install = ask "'pod' command not available in PATH. Install cocoapods (may require a sudo password) (Y/n)? "
1023
+ if install.downcase =~ /^n/
1024
+ say "Please install cocoapods or use --no-add-sdk to continue."
1025
+ exit(-1)
1026
+ end
1027
+
1028
+ gem_home = ENV["GEM_HOME"]
1029
+ if gem_home && File.writable?(gem_home)
1030
+ system_command "gem install cocoapods"
1031
+ else
1032
+ system_command "sudo gem install cocoapods"
1033
+ end
1034
+
1035
+ # Ensure master podspec repo is set up (will update if it exists).
1036
+ system_command "pod setup"
1037
+ end
1038
+
1039
+ def verify_carthage
1040
+ carthage_cmd = `which carthage`
1041
+ return unless carthage_cmd.empty?
1042
+
1043
+ brew_cmd = `which brew`
1044
+ if brew_cmd.empty?
1045
+ say "'carthage' command not available in PATH and 'brew' command not available in PATH to install 'carthage'."
1046
+ exit(-1)
1047
+ end
1048
+
1049
+ install = ask "'carthage' command not available in PATH. Use Homebrew to install carthage (Y/n)? "
1050
+ if install.downcase =~ /^n/
1051
+ say "Please install carthage or use --no-add-sdk to continue."
1052
+ exit(-1)
1053
+ end
1054
+
1055
+ system_command "brew install carthage"
1056
+ end
1057
+
1058
+ def verify_git
1059
+ return unless ConfigurationHelper.commit
1060
+
1061
+ git_cmd = `which git`
1062
+ return unless git_cmd.empty?
1063
+
1064
+ xcode_select_path = `which xcode-select`
1065
+ if xcode_select_path.empty?
1066
+ say "'git' command not available in PATH and 'xcode-select' command not available in PATH to install 'git'."
1067
+ exit(-1)
1068
+ end
1069
+
1070
+ install = ask "'git' command not available in PATH. Install Xcode command-line tools (requires password) (Y/n)? "
1071
+ if install.downcase =~ /^n/
1072
+ say "Please install Xcode command tools or leave out the --commit option to continue."
1073
+ exit(-1)
1074
+ end
1075
+
1076
+ system_command "xcode-select --install"
1077
+ end
1078
+
1079
+ def system_command(command)
1080
+ # TODO: Not working well with bundle exec atm.
1081
+ say "<%= color(\"$ #{command}\", BOLD) %>"
1082
+ system command
1083
+ end
906
1084
  end
907
1085
  end
908
1086
  end
@@ -1,3 +1,3 @@
1
1
  module BranchIOCLI
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
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.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Branch
@@ -9,8 +9,36 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-10-31 00:00:00.000000000 Z
12
+ date: 2017-11-01 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: CFPropertyList
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: cocoapods-core
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
14
42
  - !ruby/object:Gem::Dependency
15
43
  name: commander
16
44
  requirement: !ruby/object:Gem::Requirement