branch_io_cli 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  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