cocoapods 1.10.0.rc.1 → 1.11.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +237 -4
  3. data/README.md +11 -11
  4. data/lib/cocoapods/command/outdated.rb +12 -1
  5. data/lib/cocoapods/command/repo/push.rb +17 -0
  6. data/lib/cocoapods/command/spec.rb +18 -9
  7. data/lib/cocoapods/command/spec/cat.rb +3 -1
  8. data/lib/cocoapods/command/spec/lint.rb +1 -1
  9. data/lib/cocoapods/command/spec/which.rb +3 -1
  10. data/lib/cocoapods/config.rb +1 -1
  11. data/lib/cocoapods/downloader.rb +4 -2
  12. data/lib/cocoapods/downloader/cache.rb +95 -6
  13. data/lib/cocoapods/external_sources/podspec_source.rb +1 -1
  14. data/lib/cocoapods/gem_version.rb +1 -1
  15. data/lib/cocoapods/generator/acknowledgements.rb +1 -1
  16. data/lib/cocoapods/generator/app_target_helper.rb +7 -3
  17. data/lib/cocoapods/generator/copy_dsyms_script.rb +4 -4
  18. data/lib/cocoapods/generator/copy_xcframework_script.rb +4 -29
  19. data/lib/cocoapods/generator/embed_frameworks_script.rb +2 -1
  20. data/lib/cocoapods/generator/script_phase_constants.rb +1 -0
  21. data/lib/cocoapods/installer.rb +52 -4
  22. data/lib/cocoapods/installer/analyzer.rb +12 -8
  23. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +31 -4
  24. data/lib/cocoapods/installer/podfile_validator.rb +2 -2
  25. data/lib/cocoapods/installer/pre_integrate_hooks_context.rb +9 -0
  26. data/lib/cocoapods/installer/project_cache/project_cache_analyzer.rb +9 -2
  27. data/lib/cocoapods/installer/project_cache/project_installation_cache.rb +15 -2
  28. data/lib/cocoapods/installer/project_cache/target_cache_key.rb +3 -3
  29. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +106 -5
  30. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +1 -1
  31. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +15 -4
  32. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +25 -6
  33. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +6 -19
  34. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +75 -59
  35. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +48 -6
  36. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +2 -2
  37. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +2 -5
  38. data/lib/cocoapods/resolver.rb +4 -4
  39. data/lib/cocoapods/sandbox/file_accessor.rb +51 -10
  40. data/lib/cocoapods/sandbox/headers_store.rb +3 -1
  41. data/lib/cocoapods/sandbox/path_list.rb +1 -1
  42. data/lib/cocoapods/sandbox/pod_dir_cleaner.rb +1 -1
  43. data/lib/cocoapods/sources_manager.rb +14 -8
  44. data/lib/cocoapods/target.rb +1 -1
  45. data/lib/cocoapods/target/aggregate_target.rb +23 -1
  46. data/lib/cocoapods/target/build_settings.rb +56 -22
  47. data/lib/cocoapods/target/pod_target.rb +47 -22
  48. data/lib/cocoapods/user_interface.rb +4 -0
  49. data/lib/cocoapods/validator.rb +25 -5
  50. data/lib/cocoapods/version_metadata.rb +1 -1
  51. data/lib/cocoapods/xcode/xcframework.rb +8 -3
  52. data/lib/cocoapods/xcode/xcframework/xcframework_slice.rb +10 -1
  53. metadata +28 -21
@@ -122,7 +122,7 @@ module Pod
122
122
  output_path = podspecs_tmp_dir + File.basename(path)
123
123
  output_path.dirname.mkpath
124
124
  begin
125
- open(path) do |io|
125
+ OpenURI.open_uri(path) do |io|
126
126
  output_path.open('w') { |f| f << io.read }
127
127
  end
128
128
  rescue => e
@@ -16,12 +16,14 @@ module Pod
16
16
  [
17
17
  ['--regex', 'Interpret the `QUERY` as a regular expression'],
18
18
  ['--show-all', 'Print all versions of the given podspec'],
19
+ ['--version', 'Print a specific version of the given podspec'],
19
20
  ].concat(super)
20
21
  end
21
22
 
22
23
  def initialize(argv)
23
24
  @use_regex = argv.flag?('regex')
24
25
  @show_all = argv.flag?('show-all')
26
+ @version = argv.option('version')
25
27
  @query = argv.shift_argument
26
28
  @query = @query.gsub('.podspec', '') unless @query.nil?
27
29
  super
@@ -35,7 +37,7 @@ module Pod
35
37
 
36
38
  def run
37
39
  query = @use_regex ? @query : Regexp.escape(@query)
38
- UI.puts get_path_of_spec(query, @show_all)
40
+ UI.puts get_path_of_spec(query, @show_all || @version)
39
41
  end
40
42
  end
41
43
  end
@@ -163,7 +163,7 @@ module Pod
163
163
  #
164
164
  def installation_root
165
165
  @installation_root ||= begin
166
- current_dir = Pathname.new(ActiveSupport::Multibyte::Unicode.normalize(Dir.pwd))
166
+ current_dir = Pathname.new(Dir.pwd.unicode_normalize(:nfkc))
167
167
  current_path = current_dir
168
168
  until current_path.root?
169
169
  if podfile_path_in_dir(current_path)
@@ -50,8 +50,10 @@ module Pod
50
50
 
51
51
  if target && result.location && target != result.location
52
52
  UI.message "Copying #{request.name} from `#{result.location}` to #{UI.path target}", '> ' do
53
- FileUtils.rm_rf target
54
- FileUtils.cp_r(result.location, target)
53
+ Cache.read_lock(result.location) do
54
+ FileUtils.rm_rf target
55
+ FileUtils.cp_r(result.location, target)
56
+ end
55
57
  end
56
58
  end
57
59
  result
@@ -69,6 +69,91 @@ module Pod
69
69
  end
70
70
  end
71
71
 
72
+ # Convenience method for acquiring a shared lock to safely read from the
73
+ # cache. See `Cache.lock` for more details.
74
+ #
75
+ # @param [Pathname] location
76
+ # the path to require a lock for.
77
+ #
78
+ # @param [block] &block
79
+ # the block to execute inside the lock.
80
+ #
81
+ # @return [void]
82
+ #
83
+ def self.read_lock(location, &block)
84
+ Cache.lock(location, File::LOCK_SH, &block)
85
+ end
86
+
87
+ # Convenience method for acquiring an exclusive lock to safely write to
88
+ # the cache. See `Cache.lock` for more details.
89
+ #
90
+ # @param [Pathname] location
91
+ # the path to require a lock for.
92
+ #
93
+ # @param [block] &block
94
+ # the block to execute inside the lock.
95
+ #
96
+ # @return [void]
97
+ #
98
+ def self.write_lock(location, &block)
99
+ Cache.lock(location, File::LOCK_EX, &block)
100
+ end
101
+
102
+ # Creates a .lock file at `location`, aquires a lock of type
103
+ # `lock_type`, checks that it is valid, and executes passed block while
104
+ # holding on to that lock. Afterwards, the .lock file is deleted, which is
105
+ # why validation of the lock is necessary, as you might have a lock on a
106
+ # file that doesn't exist on the filesystem anymore.
107
+ #
108
+ # @param [Pathname] location
109
+ # the path to require a lock for.
110
+ #
111
+ # @param [locking_constant] lock_type
112
+ # the type of lock, either exclusive (File::LOCK_EX) or shared
113
+ # (File::LOCK_SH).
114
+ #
115
+ # @return [void]
116
+ #
117
+ def self.lock(location, lock_type)
118
+ raise ArgumentError, 'no block given' unless block_given?
119
+ lockfile = "#{location}.lock"
120
+ f = nil
121
+ loop do
122
+ f.close if f
123
+ f = File.open(lockfile, File::CREAT, 0o644)
124
+ f.flock(lock_type)
125
+ break if Cache.valid_lock?(f, lockfile)
126
+ end
127
+ begin
128
+ yield location
129
+ ensure
130
+ if lock_type == File::LOCK_SH
131
+ f.flock(File::LOCK_EX)
132
+ File.delete(lockfile) if Cache.valid_lock?(f, lockfile)
133
+ else
134
+ File.delete(lockfile)
135
+ end
136
+ f.close
137
+ end
138
+ end
139
+
140
+ # Checks that the lock is on a file that still exists on the filesystem.
141
+ #
142
+ # @param [File] file
143
+ # the actual file that we have a lock for.
144
+ #
145
+ # @param [String] filename
146
+ # the filename of the file that we have a lock for.
147
+ #
148
+ # @return [Boolean]
149
+ # true if `filename` still exists and is the same file as `file`
150
+ #
151
+ def self.valid_lock?(file, filename)
152
+ file.stat.ino == File.stat(filename).ino
153
+ rescue Errno::ENOENT
154
+ false
155
+ end
156
+
72
157
  private
73
158
 
74
159
  # Ensures the cache on disk was created with the same CocoaPods version as
@@ -112,7 +197,7 @@ module Pod
112
197
  #
113
198
  def path_for_spec(request, slug_opts = {})
114
199
  path = root + 'Specs' + request.slug(**slug_opts)
115
- path.sub_ext('.podspec.json')
200
+ Pathname.new(path.to_path + '.podspec.json')
116
201
  end
117
202
 
118
203
  # @param [Request] request
@@ -197,10 +282,12 @@ module Pod
197
282
  def copy_and_clean(source, destination, spec)
198
283
  specs_by_platform = group_subspecs_by_platform(spec)
199
284
  destination.parent.mkpath
200
- FileUtils.rm_rf(destination)
201
- FileUtils.cp_r(source, destination)
202
- Pod::Installer::PodSourcePreparer.new(spec, destination).prepare!
203
- Sandbox::PodDirCleaner.new(destination, specs_by_platform).clean!
285
+ Cache.write_lock(destination) do
286
+ FileUtils.rm_rf(destination)
287
+ FileUtils.cp_r(source, destination)
288
+ Pod::Installer::PodSourcePreparer.new(spec, destination).prepare!
289
+ Sandbox::PodDirCleaner.new(destination, specs_by_platform).clean!
290
+ end
204
291
  end
205
292
 
206
293
  def group_subspecs_by_platform(spec)
@@ -226,7 +313,9 @@ module Pod
226
313
  #
227
314
  def write_spec(spec, path)
228
315
  path.dirname.mkpath
229
- path.open('w') { |f| f.write spec.to_pretty_json }
316
+ Cache.write_lock(path) do
317
+ path.open('w') { |f| f.write spec.to_pretty_json }
318
+ end
230
319
  end
231
320
  end
232
321
  end
@@ -16,7 +16,7 @@ module Pod
16
16
  else
17
17
  require 'cocoapods/open-uri'
18
18
  begin
19
- open(podspec_uri) { |io| store_podspec(sandbox, io.read, is_json) }
19
+ OpenURI.open_uri(podspec_uri) { |io| store_podspec(sandbox, io.read, is_json) }
20
20
  rescue OpenURI::HTTPError => e
21
21
  status = e.io.status.join(' ')
22
22
  raise Informative, "Failed to fetch podspec for `#{name}` at `#{podspec_uri}`.\n Error: #{status}"
@@ -1,5 +1,5 @@
1
1
  module Pod
2
2
  # The version of the CocoaPods command line tool.
3
3
  #
4
- VERSION = '1.10.0.rc.1'.freeze unless defined? Pod::VERSION
4
+ VERSION = '1.11.0.beta.1'.freeze unless defined? Pod::VERSION
5
5
  end
@@ -67,7 +67,7 @@ module Pod
67
67
  # the specification for which license is needed.
68
68
  #
69
69
  # @return [String] The text of the license.
70
- # @return [Nil] If not license text could be found.
70
+ # @return [Nil] If no license text could be found.
71
71
  #
72
72
  def license_text(spec)
73
73
  return nil unless spec.license
@@ -9,7 +9,7 @@ module Pod
9
9
  # @param [Project] project
10
10
  # the Xcodeproj to generate the target into.
11
11
  #
12
- # @param [Symbol] platform
12
+ # @param [Symbol] platform_name
13
13
  # the platform of the target. Can be `:ios` or `:osx`, etc.
14
14
  #
15
15
  # @param [String] deployment_target
@@ -18,10 +18,14 @@ module Pod
18
18
  # @param [String] name
19
19
  # The name to use for the target, defaults to 'App'.
20
20
  #
21
+ # @param [String] product_basename
22
+ # The product basename to use for the target, defaults to `name`.
23
+ #
21
24
  # @return [PBXNativeTarget] the new target that was created.
22
25
  #
23
- def self.add_app_target(project, platform, deployment_target, name = 'App')
24
- project.new_target(:application, name, platform, deployment_target)
26
+ def self.add_app_target(project, platform_name, deployment_target, name = 'App', product_basename = nil)
27
+ project.new_target(:application, name, platform_name, deployment_target, nil,
28
+ nil, product_basename)
25
29
  end
26
30
 
27
31
  # Creates and links an import file for the given pod target and into the given native target.
@@ -1,18 +1,18 @@
1
1
  module Pod
2
2
  module Generator
3
3
  class CopydSYMsScript
4
- # @return [Array<Pathname>] dsym_paths the dSYM paths to include in the script contents.
4
+ # @return [Array<Pathname, String>] dsym_paths the dSYM paths to include in the script contents.
5
5
  #
6
6
  attr_reader :dsym_paths
7
7
 
8
- # @return [Array<Pathname>] bcsymbolmap_paths the bcsymbolmap paths to include in the script contents.
8
+ # @return [Array<Pathname, String>] bcsymbolmap_paths the bcsymbolmap paths to include in the script contents.
9
9
  #
10
10
  attr_reader :bcsymbolmap_paths
11
11
 
12
12
  # Initialize a new instance
13
13
  #
14
- # @param [Array<Pathname>] dsym_paths @see dsym_paths
15
- # @param [Array<Pathname>] bcsymbolmap_paths @see bcsymbolmap_paths
14
+ # @param [Array<Pathname, String>] dsym_paths @see dsym_paths
15
+ # @param [Array<Pathname, String>] bcsymbolmap_paths @see bcsymbolmap_paths
16
16
  #
17
17
  def initialize(dsym_paths, bcsymbolmap_paths)
18
18
  @dsym_paths = Array(dsym_paths)
@@ -157,22 +157,6 @@ install_framework()
157
157
  echo "Copied $source to $destination"
158
158
  }
159
159
 
160
- install_xcframework_library() {
161
- local basepath="$1"
162
- local name="$2"
163
- local paths=("$@")
164
-
165
- # Locate the correct slice of the .xcframework for the current architectures
166
- select_slice "${paths[@]}"
167
- local target_path="$SELECT_SLICE_RETVAL"
168
- if [[ -z "$target_path" ]]; then
169
- echo "warning: [CP] Unable to find matching .xcframework slice in '${paths[@]}' for the current build architectures ($ARCHS)."
170
- return
171
- fi
172
-
173
- install_framework "$basepath/$target_path" "$name"
174
- }
175
-
176
160
  install_xcframework() {
177
161
  local basepath="$1"
178
162
  local name="$2"
@@ -194,12 +178,8 @@ install_xcframework() {
194
178
  mkdir -p "$destination"
195
179
  fi
196
180
 
197
- if [[ "$package_type" == "library" ]]; then
198
- # Libraries can contain headers, module maps, and a binary, so we'll copy everything in the folder over
199
- copy_dir "$source/" "$destination"
200
- elif [[ "$package_type" == "framework" ]]; then
201
- copy_dir "$source" "$destination"
202
- fi
181
+ copy_dir "$source/" "$destination"
182
+
203
183
  echo "Copied $source to $destination"
204
184
  }
205
185
 
@@ -222,16 +202,11 @@ install_xcframework() {
222
202
  def install_xcframework_args(xcframework, slices)
223
203
  root = xcframework.path
224
204
  args = [shell_escape("${PODS_ROOT}/#{root.relative_path_from(sandbox_root)}")]
225
- args << shell_escape(xcframework.name)
205
+ args << shell_escape(xcframework.target_name)
226
206
  is_framework = xcframework.build_type.framework?
227
207
  args << shell_escape(is_framework ? 'framework' : 'library')
228
208
  slices.each do |slice|
229
- args << if is_framework
230
- shell_escape(slice.path.relative_path_from(root))
231
- else
232
- # We don't want the path to the library binary, we want the dir that contains it
233
- shell_escape(slice.path.dirname.relative_path_from(root))
234
- end
209
+ args << shell_escape(slice.path.dirname.relative_path_from(root))
235
210
  end
236
211
  args.join(' ')
237
212
  end
@@ -159,8 +159,9 @@ code_sign_if_enabled() {
159
159
  end
160
160
  xcframeworks_by_config.each do |config, xcframeworks|
161
161
  xcframeworks.select { |xcf| xcf.build_type.dynamic_framework? }.each do |xcframework|
162
+ target_name = xcframework.target_name
162
163
  name = xcframework.name
163
- contents_by_config[config] << %( install_framework "#{Target::BuildSettings::XCFRAMEWORKS_BUILD_DIR_VARIABLE}/#{name}/#{name}.framework"\n)
164
+ contents_by_config[config] << %( install_framework "#{Target::BuildSettings::XCFRAMEWORKS_BUILD_DIR_VARIABLE}/#{target_name}/#{name}.framework"\n)
164
165
  end
165
166
  end
166
167
  script << "\n" unless contents_by_config.empty?
@@ -79,6 +79,7 @@ install_dsym() {
79
79
  rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --links --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
80
80
  else
81
81
  # The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
82
+ mkdir -p "${DWARF_DSYM_FOLDER_PATH}"
82
83
  touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.dSYM"
83
84
  fi
84
85
  fi
@@ -36,6 +36,7 @@ module Pod
36
36
  autoload :PreInstallHooksContext, 'cocoapods/installer/pre_install_hooks_context'
37
37
  autoload :BaseInstallHooksContext, 'cocoapods/installer/base_install_hooks_context'
38
38
  autoload :PostIntegrateHooksContext, 'cocoapods/installer/post_integrate_hooks_context'
39
+ autoload :PreIntegrateHooksContext, 'cocoapods/installer/pre_integrate_hooks_context'
39
40
  autoload :SourceProviderHooksContext, 'cocoapods/installer/source_provider_hooks_context'
40
41
  autoload :PodfileValidator, 'cocoapods/installer/podfile_validator'
41
42
  autoload :PodSourceInstaller, 'cocoapods/installer/pod_source_installer'
@@ -175,6 +176,7 @@ module Pod
175
176
  end
176
177
 
177
178
  def integrate
179
+ run_podfile_pre_integrate_hooks
178
180
  generate_pods_project
179
181
  if installation_options.integrate_targets?
180
182
  integrate_user_project
@@ -199,7 +201,7 @@ module Pod
199
201
 
200
202
  force_clean_install = clean_install || project_cache_version.version != Version.create(VersionMetadata.project_cache_version)
201
203
  cache_result = ProjectCache::ProjectCacheAnalyzer.new(sandbox, installation_cache, analysis_result.all_user_build_configurations,
202
- object_version, plugins, pod_targets, aggregate_targets, :clean_install => force_clean_install).analyze
204
+ object_version, plugins, pod_targets, aggregate_targets, installation_options.to_h, :clean_install => force_clean_install).analyze
203
205
  aggregate_targets_to_generate = cache_result.aggregate_targets_to_generate || []
204
206
  pod_targets_to_generate = cache_result.pod_targets_to_generate
205
207
  (aggregate_targets_to_generate + pod_targets_to_generate).each do |target|
@@ -627,6 +629,15 @@ module Pod
627
629
  title_options)
628
630
  end
629
631
 
632
+ # Runs the registered callbacks for the plugins pre integrate hooks.
633
+ #
634
+ def run_plugins_pre_integrate_hooks
635
+ if any_plugin_pre_integrate_hooks?
636
+ context = PreIntegrateHooksContext.generate(sandbox, pods_project, aggregate_targets)
637
+ HooksManager.run(:pre_integrate, context, plugins)
638
+ end
639
+ end
640
+
630
641
  # Runs the registered callbacks for the plugins post install hooks.
631
642
  #
632
643
  def run_plugins_post_install_hooks
@@ -650,6 +661,12 @@ module Pod
650
661
  end
651
662
  end
652
663
 
664
+ # @return [Boolean] whether there are any plugin pre-integrate hooks to run
665
+ #
666
+ def any_plugin_pre_integrate_hooks?
667
+ HooksManager.hooks_to_run(:pre_integrate, plugins).any?
668
+ end
669
+
653
670
  # @return [Boolean] whether there are any plugin post-install hooks to run
654
671
  #
655
672
  def any_plugin_post_install_hooks?
@@ -747,7 +764,7 @@ module Pod
747
764
  def warn_for_installed_script_phases
748
765
  pods_to_install = sandbox_state.added | sandbox_state.changed
749
766
  pod_targets.group_by(&:pod_name).each do |name, pod_targets|
750
- if pods_to_install.include?(name)
767
+ if pods_to_install.include?(name) && !sandbox.local?(name)
751
768
  script_phase_count = pod_targets.inject(0) { |sum, target| sum + target.script_phases.count }
752
769
  unless script_phase_count.zero?
753
770
  UI.warn "#{name} has added #{script_phase_count} #{'script phase'.pluralize(script_phase_count)}. " \
@@ -766,9 +783,11 @@ module Pod
766
783
  #
767
784
  def warn_for_removing_git_master_specs_repo
768
785
  return unless installation_options.warn_for_unused_master_specs_repo?
769
- podfile_master_source = podfile.sources.find { |source| source == MASTER_SPECS_REPO_GIT_URL }
786
+ plugin_sources = run_source_provider_hooks
787
+ all_sources = podfile.sources + plugin_sources.map(&:url)
788
+ master_source = all_sources.find { |source| source == MASTER_SPECS_REPO_GIT_URL }
770
789
  master_repo = config.sources_manager.all.find { |s| s.url == MASTER_SPECS_REPO_GIT_URL }
771
- if podfile_master_source.nil? && !master_repo.nil?
790
+ if master_source.nil? && !master_repo.nil?
772
791
  UI.warn 'Your project does not explicitly specify the CocoaPods master specs repo. Since CDN is now used as the' \
773
792
  ' default, you may safely remove it from your repos directory via `pod repo remove master`. To suppress this warning' \
774
793
  ' please add `warn_for_unused_master_specs_repo => false` to your Podfile.'
@@ -815,6 +834,7 @@ module Pod
815
834
  installation_cache.update_project_object_version!(cache_analysis_result.project_object_version)
816
835
  installation_cache.update_build_configurations!(cache_analysis_result.build_configurations)
817
836
  installation_cache.update_podfile_plugins!(plugins)
837
+ installation_cache.update_installation_options!(installation_options.to_h)
818
838
  installation_cache.save_as(sandbox.project_installation_cache_path)
819
839
 
820
840
  metadata_cache.update_metadata!(target_installation_results.pod_target_installation_results || {},
@@ -873,6 +893,34 @@ module Pod
873
893
  "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
874
894
  end
875
895
 
896
+ # Runs the post integrate hooks of the installed specs and of the Podfile.
897
+ #
898
+ # @note Post integrate hooks run _after_ saving of project, so that they
899
+ # can alter it after it is written to the disk.
900
+ #
901
+ # @return [void]
902
+ #
903
+ def run_podfile_pre_integrate_hooks
904
+ UI.message '- Running pre integrate hooks' do
905
+ executed = run_podfile_pre_integrate_hook
906
+ UI.message '- Podfile' if executed
907
+ end
908
+ end
909
+
910
+ # Runs the pre integrate hook of the Podfile.
911
+ #
912
+ # @raise Raises an informative if the hooks raises.
913
+ #
914
+ # @return [Boolean] Whether the hook was run.
915
+ #
916
+ def run_podfile_pre_integrate_hook
917
+ podfile.pre_integrate!(self)
918
+ rescue => e
919
+ raise Informative, 'An error occurred while processing the pre-integrate ' \
920
+ 'hook of the Podfile.' \
921
+ "\n\n#{e.message}\n\n#{e.backtrace * "\n"}"
922
+ end
923
+
876
924
  # Runs the post install hooks of the installed specs and of the Podfile.
877
925
  #
878
926
  # @note Post install hooks run _before_ saving of project, so that they