cocoapods 1.10.0 → 1.11.0.beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +237 -5
  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 +2 -18
  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 +7 -4
  29. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +149 -9
  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 +10 -3
  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 +70 -58
  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 +57 -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 +45 -20
  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
@@ -16,6 +16,7 @@ module Pod
16
16
  [
17
17
  ['--regex', 'Interpret the `QUERY` as a regular expression'],
18
18
  ['--show-all', 'Pick from 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
 
@@ -24,6 +25,7 @@ module Pod
24
25
  @show_all = argv.flag?('show-all')
25
26
  @query = argv.shift_argument
26
27
  @query = @query.gsub('.podspec', '') unless @query.nil?
28
+ @version = argv.option('version')
27
29
  super
28
30
  end
29
31
 
@@ -40,7 +42,7 @@ module Pod
40
42
  index = UI.choose_from_array(specs, "Which spec would you like to print [1-#{specs.count}]? ")
41
43
  specs[index]
42
44
  else
43
- get_path_of_spec(query)
45
+ get_path_of_spec(query, @version)
44
46
  end
45
47
 
46
48
  UI.puts File.read(filepath)
@@ -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'.freeze unless defined? Pod::VERSION
4
+ VERSION = '1.11.0.beta.2'.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,27 +157,11 @@ 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"
179
163
  local package_type="$3"
180
- local paths=("$@")
164
+ local paths=("${@:3}")
181
165
 
182
166
  # Locate the correct slice of the .xcframework for the current architectures
183
167
  select_slice "${paths[@]}"
@@ -218,7 +202,7 @@ install_xcframework() {
218
202
  def install_xcframework_args(xcframework, slices)
219
203
  root = xcframework.path
220
204
  args = [shell_escape("${PODS_ROOT}/#{root.relative_path_from(sandbox_root)}")]
221
- args << shell_escape(xcframework.name)
205
+ args << shell_escape(xcframework.target_name)
222
206
  is_framework = xcframework.build_type.framework?
223
207
  args << shell_escape(is_framework ? 'framework' : 'library')
224
208
  slices.each do |slice|
@@ -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