Class: BranchIOCLI::Helper::ToolHelper

Inherits:
Object
  • Object
show all
Extended by:
Methods
Defined in:
lib/branch_io_cli/helper/tool_helper.rb

Class Method Summary collapse

Methods included from Methods

clear, confirm, sh

Class Method Details

.add_carthage(options) ⇒ Object



67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 67

def add_carthage(options)
  # TODO: Collapse this and Command::update_cartfile
  verify_carthage

  # 1. Generate Cartfile
  cartfile_path = options.cartfile_path
  File.open(cartfile_path, "w") do |file|
    file.write <<-EOF
github "BranchMetrics/ios-branch-deep-linking"
    EOF
  end

  # 2. carthage update
  sh "carthage", options.carthage_command, chdir: File.dirname(config.cartfile_path)

  # 3. Add Cartfile and Cartfile.resolved to commit (in case :commit param specified)
  helper.add_change cartfile_path
  helper.add_change "#{cartfile_path}.resolved"
  helper.add_change options.xcodeproj_path

  # 4. Add to target dependencies
  frameworks_group = options.xcodeproj.frameworks_group
  branch_framework = frameworks_group.new_file "Carthage/Build/iOS/Branch.framework"
  target = options.target
  target.frameworks_build_phase.add_file_reference branch_framework

  # 5. Create a copy-frameworks build phase
  carthage_build_phase = target.new_shell_script_build_phase "carthage copy-frameworks"
  carthage_build_phase.shell_script = "/usr/local/bin/carthage copy-frameworks"

  carthage_build_phase.input_paths << "$(SRCROOT)/Carthage/Build/iOS/Branch.framework"
  carthage_build_phase.output_paths << "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Branch.framework"

  update_framework_search_paths "$(SRCROOT)/Carthage/Build/iOS"

  options.xcodeproj.save

  return unless options.commit

  # For now, add Carthage folder to SCM

  # 6. Add the Carthage folder to the commit (in case :commit param specified)
  carthage_folder_path = Pathname.new(File.expand_path("../Carthage", cartfile_path)).relative_path_from(Pathname.pwd)
  cartfile_pathname = Pathname.new(cartfile_path).relative_path_from Pathname.pwd
  helper.add_change carthage_folder_path
  sh "git", "add", cartfile_pathname.to_s, "#{cartfile_pathname}.resolved", carthage_folder_path.to_s
end

.add_cocoapods(options) ⇒ Object



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 26

def add_cocoapods(options)
  verify_cocoapods

  podfile_path = options.podfile_path

  install_command = %w(pod install)
  install_command << "--repo-update" if options.pod_repo_update
  Dir.chdir(File.dirname(podfile_path)) do
    sh %w(pod init)
    PatternPatch::Patch.new(
      regexp: /^(\s*)# Pods for #{options.target.name}$/,
      mode: :append,
      text: "\n\\1pod \"Branch\""
    ).apply podfile_path
    # Store a Pod::Podfile representation of this file.
    options.open_podfile
    sh(*install_command)
  end

  return unless options.commit

  helper.add_change podfile_path
  helper.add_change "#{podfile_path}.lock"

  # For now, add Pods folder to SCM.
  pods_folder_path = Pathname.new(File.expand_path("../Pods", podfile_path)).relative_path_from Pathname.pwd
  workspace_path = Pathname.new(File.expand_path(options.xcodeproj_path.sub(/.xcodeproj$/, ".xcworkspace"))).relative_path_from Pathname.pwd
  podfile_pathname = Pathname.new(podfile_path).relative_path_from Pathname.pwd
  helper.add_change pods_folder_path
  helper.add_change workspace_path

  sh(
    "git",
    "add",
    podfile_pathname.to_s,
    "#{podfile_pathname}.lock",
    pods_folder_path.to_s,
    workspace_path.to_s
  )
end

.add_direct(options) ⇒ Object



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 115

def add_direct(options)
  # Put the framework in the path for any existing Frameworks group in the project.
  frameworks_group = options.xcodeproj.frameworks_group
  framework_path = File.join frameworks_group.real_path, "Branch.framework"
  raise "#{framework_path} exists." if File.exist? framework_path

  say "Finding current framework release"

  # Find the latest release from GitHub.
  releases = JSON.parse helper.fetch "https://api.github.com/repos/BranchMetrics/ios-branch-deep-linking/releases"
  current_release = releases.first
  # Get the download URL for the framework.
  framework_asset = current_release["assets"][0]
  framework_url = framework_asset["browser_download_url"]

  say "Downloading Branch.framework v. #{current_release['tag_name']} (#{framework_asset['size']} bytes zipped)"

  Dir.mktmpdir do |download_folder|
    zip_path = File.join download_folder, "Branch.framework.zip"

    File.unlink zip_path if File.exist? zip_path

    # Download the framework zip
    helper.download framework_url, zip_path, size: framework_asset["size"]

    say "Unzipping Branch.framework"

    # Unzip
    Zip::File.open zip_path do |zip_file|
      # Start with just the framework and add dSYM, etc., later
      zip_file.glob "Carthage/Build/iOS/Branch.framework/**/*" do |entry|
        filename = entry.name.sub %r{^Carthage/Build/iOS}, frameworks_group.real_path.to_s
        FileUtils.mkdir_p File.dirname filename
        entry.extract filename
      end
    end
  end

  # Now the current framework is in framework_path

  say "Adding to #{options.xcodeproj_path}"

  # Add as a dependency in the Frameworks group
  framework = frameworks_group.new_file "Branch.framework" # relative to frameworks_group.real_path
  options.target.frameworks_build_phase.add_file_reference framework, true

  update_framework_search_paths "$(SRCROOT)"

  options.xcodeproj.save

  helper.add_change options.xcodeproj_path
  helper.add_change framework_path
  sh "git", "add", framework_path if options.commit
end

.carthage_bootstrap_if_required(report = STDOUT) ⇒ Object



393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 393

def carthage_bootstrap_if_required(report = STDOUT)
  return true unless config.cartfile_path
  return true if Dir.exist?(File.join(File.dirname(config.cartfile_path), "Carthage", "Build", "iOS"))

  say "carthage checkout required in order to build."
  if config.confirm
    install = confirm 'Run "carthage checkout && carthage build --platform ios" now?', true

    unless install
      say 'Please build your Carthage dependencies first in order to continue.'
      return false
    end
  end

  verify_carthage

  checkout_command = %w(carthage checkout)

  # included by sh, but this is to the screen when generating a report.
  say "Running #{IO.command_from_args(*checkout_command)}"
  if report.sh(*checkout_command).success?
    say "Done ✅"
  else
    say "#{IO.command_from_args(*checkout_command)} failed. See report for details."
    return false
  end

  build_command = %w(carthage build --platform ios)

  # included by sh, but this is to the screen when generating a report.
  say "Running #{IO.command_from_args(*build_command)}"
  if report.sh(*build_command).success?
    say "Done ✅"
  else
    say "#{IO.command_from_args(*build_command)} failed. See report for details."
    return false
  end

  true
end

.configObject



14
15
16
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 14

def config
  Configuration::Configuration.current
end

.envObject



18
19
20
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 18

def env
  Configuration::Environment
end

.helperObject



22
23
24
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 22

def helper
  BranchHelper
end

.pod_install_if_required(report = STDOUT) ⇒ Object



353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 353

def pod_install_if_required(report = STDOUT)
  return true unless config.pod_install_required?
  # Only if a Podfile is detected/supplied at the command line.

  say "pod install required in order to build."
  if config.confirm
    install = confirm 'Run "pod install" now?', true

    unless install
      say 'Please run "pod install" or "pod update" first in order to continue.'
      return false
    end
  end

  verify_cocoapods

  install_command = %w(pod install)

  if config.pod_repo_update
    install_command << " --repo-update"
  else
    say <<-EOF
You have disabled "pod repo update". This can cause "pod install" to fail in
some cases. If that happens, please rerun without --no-pod-repo-update or run
"pod install --repo-update" manually.
        EOF
  end

  # included by sh, but this is to the screen when generating a report.
  say "Running #{IO.command_from_args(*install_command)}"
  if report.sh(*install_command).success?
    say "Done ✅"
  else
    say "#{IO.command_from_args(*install_command)} failed. See report for details."
    return false
  end

  true
end

.update_cartfile(options, project) ⇒ Object



218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 218

def update_cartfile(options, project)
  verify_carthage

  cartfile_path = options.cartfile_path
  return false if cartfile_path.nil?

  # 1. Patch Cartfile. Return if no change (Branch already present).
  return false unless PatchHelper.patch_cartfile cartfile_path

  # 2. carthage bootstrap (or other command)
  cmd = ["carthage", *options.carthage_command.shellsplit]
  cmd << "ios-branch-deep-linking" if options.carthage_command =~ /^(update|build)/
  sh(*cmd, chdir: File.dirname(config.cartfile_path))

  # 3. Add Cartfile and Cartfile.resolved to commit (in case :commit param specified)
  helper.add_change cartfile_path
  helper.add_change "#{cartfile_path}.resolved"
  helper.add_change options.xcodeproj_path

  # 4. Add to target dependencies
  frameworks_group = project.frameworks_group
  branch_framework = frameworks_group.new_file "Carthage/Build/iOS/Branch.framework"
  target = options.target
  target.frameworks_build_phase.add_file_reference branch_framework

  # 5. Add to copy-frameworks build phase
  carthage_build_phase = target.build_phases.find do |phase|
    phase.respond_to?(:shell_script) && phase.shell_script =~ /carthage\s+copy-frameworks/
  end

  if carthage_build_phase
    carthage_build_phase.input_paths << "$(SRCROOT)/Carthage/Build/iOS/Branch.framework"
    carthage_build_phase.output_paths << "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Branch.framework"
  end

  # 6. Check if Carthage folder is under SCM
  carthage_folder_path = Pathname.new(File.expand_path("../Carthage", cartfile_path)).relative_path_from Pathname.pwd
  `git ls-files #{carthage_folder_path.to_s.shellescape} --error-unmatch > /dev/null 2>&1`
  return true unless $?.exitstatus == 0

  # 7. If so, add the Carthage folder to the commit (in case :commit param specified)
  helper.add_change carthage_folder_path
  sh "git", "add", carthage_folder_path.to_s if options.commit

  true
end

.update_framework_search_paths(path) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 170

def update_framework_search_paths(path)
  # Make sure this is in the FRAMEWORK_SEARCH_PATHS if we just added it.
  if config.xcodeproj.frameworks_group.files.count == 1
    target = config.target
    target.build_configurations.each do |c|
      # this accounts for project-level settings as well
      setting = target.resolved_build_setting("FRAMEWORK_SEARCH_PATHS")[c.name] || []
      next if setting.include?(path) || setting.include?("#{path}/**")
      setting << path

      c.build_settings["FRAMEWORK_SEARCH_PATHS"] = setting
    end
  end
  # If it already existed, it's almost certainly already in FRAMEWORK_SEARCH_PATHS.
end

.update_podfile(options) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 186

def update_podfile(options)
  verify_cocoapods

  podfile_path = options.podfile_path
  return false if podfile_path.nil?

  # 1. Patch Podfile. Return if no change (Branch pod already present).
  return false unless PatchHelper.patch_podfile podfile_path

  # 2. pod install
  # command = "PATH='#{ENV['PATH']}' pod install"
  command = %w(pod install)
  command << '--repo-update' if options.pod_repo_update

  sh(*command, chdir: File.dirname(config.podfile_path))

  # 3. Add Podfile and Podfile.lock to commit (in case :commit param specified)
  helper.add_change podfile_path
  helper.add_change "#{podfile_path}.lock"

  # 4. Check if Pods folder is under SCM
  pods_folder_path = Pathname.new(File.expand_path("../Pods", podfile_path)).relative_path_from Pathname.pwd
  `git ls-files #{pods_folder_path.to_s.shellescape} --error-unmatch > /dev/null 2>&1`
  return true unless $?.exitstatus == 0

  # 5. If so, add the Pods folder to the commit (in case :commit param specified)
  helper.add_change pods_folder_path
  sh "git", "add", pods_folder_path.to_s if options.commit

  true
end

.verify_carthageObject



313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 313

def verify_carthage
  carthage_cmd = `which carthage`
  return unless carthage_cmd.empty?

  brew_cmd = `which brew`
  if brew_cmd.empty?
    say "'carthage' command not available in PATH and 'brew' command not available in PATH to install 'carthage'."
    exit(-1)
  end

  install = confirm "'carthage' command not available in PATH. Use Homebrew to install carthage?", true
  unless install
    say "Please install carthage or use --no-add-sdk to continue."
    exit(-1)
  end

  sh %w(brew install carthage)
end

.verify_cocoapodsObject



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 265

def verify_cocoapods
  if defined?(Bundler)
    begin
      require "cocoapods"
    rescue LoadError
      # The only alternative here would be something like patch Gemfile, run bundle install
      # and then exec %w(bundle exec br) + ARGV, except merge anything inferred or obtained
      # by asking questions.
      say %(CocoaPods is required to continue. Please add 'gem "cocoapods"' to your Gemfile, run bundle install and then rerun this command.)
      exit(-1)
    end
  end

  pod_cmd = `which pod`
  return unless pod_cmd.empty?

  cmd = `which #{install_cmd}`
  if cmd.empty?
    say "'pod' command not available in PATH and '#{install_command}' command not available in PATH to install cocoapods."
    exit(-1)
  end

  sudo = env.from_homebrew? || File.writable?(Gem.dir) ? "" : "sudo "
  sudo_warning = sudo.blank? ? "" : " (requires a sudo password)"

  install = confirm "'pod' command not available in PATH. Install cocoapods#{sudo_warning}?", true
  unless install
    # TODO: There are times that --no-add-sdk is not available or doesn't avoid the need.
    say "Please install cocoapods or use --no-add-sdk to continue."
    exit(-1)
  end

  install_cmd = env.from_homebrew? ? "brew" : "gem"

  if sudo.blank?
    command = [install_cmd.to_s, "install", "cocoapods"]
  else
    command = [sudo, install_cmd.to_s, "install", "cocoapods"]
  end

  sh(*command)

  # Ensure master podspec repo is set up (will update if it exists).
  say "Synching master podspec repo. This may take some time."
  sh %w(pod setup)
  say "Done ✅"
end

.verify_gitObject



332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
# File 'lib/branch_io_cli/helper/tool_helper.rb', line 332

def verify_git
  return unless config.commit

  git_cmd = `which git`
  return unless git_cmd.empty?

  xcode_select_path = `which xcode-select`
  if xcode_select_path.empty?
    say "'git' command not available in PATH and 'xcode-select' command not available in PATH to install 'git'."
    exit(-1)
  end

  install = confirm "'git' command not available in PATH. Install Xcode command-line tools (requires password)?", true
  unless install
    say "Please install Xcode command tools or leave out the --commit option to continue."
    exit(-1)
  end

  sh %w(xcode-select --install)
end