cocoapods 1.5.3 → 1.6.0.beta.1

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +200 -0
  3. data/lib/cocoapods.rb +0 -1
  4. data/lib/cocoapods/command/init.rb +1 -1
  5. data/lib/cocoapods/command/install.rb +7 -0
  6. data/lib/cocoapods/command/lib/lint.rb +8 -1
  7. data/lib/cocoapods/command/outdated.rb +2 -7
  8. data/lib/cocoapods/command/repo/add.rb +1 -1
  9. data/lib/cocoapods/command/repo/list.rb +1 -1
  10. data/lib/cocoapods/command/repo/push.rb +17 -12
  11. data/lib/cocoapods/command/repo/remove.rb +1 -1
  12. data/lib/cocoapods/command/repo/update.rb +1 -1
  13. data/lib/cocoapods/command/setup.rb +1 -1
  14. data/lib/cocoapods/command/spec/create.rb +39 -39
  15. data/lib/cocoapods/command/spec/lint.rb +8 -1
  16. data/lib/cocoapods/config.rb +13 -2
  17. data/lib/cocoapods/downloader/cache.rb +1 -1
  18. data/lib/cocoapods/executable.rb +2 -2
  19. data/lib/cocoapods/external_sources.rb +7 -4
  20. data/lib/cocoapods/external_sources/abstract_external_source.rb +23 -13
  21. data/lib/cocoapods/gem_version.rb +1 -1
  22. data/lib/cocoapods/generator/acknowledgements/markdown.rb +6 -0
  23. data/lib/cocoapods/generator/acknowledgements/plist.rb +11 -0
  24. data/lib/cocoapods/generator/app_target_helper.rb +102 -16
  25. data/lib/cocoapods/generator/copy_resources_script.rb +6 -0
  26. data/lib/cocoapods/generator/dummy_source.rb +14 -5
  27. data/lib/cocoapods/generator/embed_frameworks_script.rb +13 -2
  28. data/lib/cocoapods/generator/header.rb +1 -1
  29. data/lib/cocoapods/generator/info_plist_file.rb +12 -4
  30. data/lib/cocoapods/generator/prefix_header.rb +2 -2
  31. data/lib/cocoapods/hooks_manager.rb +28 -17
  32. data/lib/cocoapods/installer.rb +103 -42
  33. data/lib/cocoapods/installer/analyzer.rb +362 -277
  34. data/lib/cocoapods/installer/analyzer/analysis_result.rb +52 -22
  35. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +9 -6
  36. data/lib/cocoapods/installer/analyzer/pod_variant.rb +4 -5
  37. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +3 -14
  38. data/lib/cocoapods/installer/analyzer/specs_state.rb +28 -4
  39. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +24 -16
  40. data/lib/cocoapods/installer/analyzer/target_inspector.rb +17 -11
  41. data/lib/cocoapods/installer/pod_source_installer.rb +31 -43
  42. data/lib/cocoapods/installer/post_install_hooks_context.rb +71 -46
  43. data/lib/cocoapods/installer/pre_install_hooks_context.rb +22 -13
  44. data/lib/cocoapods/installer/source_provider_hooks_context.rb +3 -1
  45. data/lib/cocoapods/installer/user_project_integrator.rb +0 -2
  46. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +38 -28
  47. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +44 -11
  48. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +129 -119
  49. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +25 -16
  50. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +95 -0
  51. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +12 -45
  52. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +277 -169
  53. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +31 -24
  54. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +93 -0
  55. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +60 -69
  56. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +72 -0
  57. data/lib/cocoapods/installer/xcode/target_validator.rb +15 -9
  58. data/lib/cocoapods/project.rb +14 -14
  59. data/lib/cocoapods/resolver.rb +38 -50
  60. data/lib/cocoapods/sandbox.rb +22 -38
  61. data/lib/cocoapods/sandbox/file_accessor.rb +11 -6
  62. data/lib/cocoapods/sandbox/headers_store.rb +9 -8
  63. data/lib/cocoapods/sandbox/path_list.rb +5 -8
  64. data/lib/cocoapods/sources_manager.rb +1 -1
  65. data/lib/cocoapods/target.rb +92 -37
  66. data/lib/cocoapods/target/aggregate_target.rb +140 -84
  67. data/lib/cocoapods/target/build_settings.rb +1076 -0
  68. data/lib/cocoapods/target/pod_target.rb +198 -294
  69. data/lib/cocoapods/user_interface.rb +5 -0
  70. data/lib/cocoapods/validator.rb +133 -41
  71. metadata +18 -18
  72. data/lib/cocoapods/generator/xcconfig.rb +0 -13
  73. data/lib/cocoapods/generator/xcconfig/aggregate_xcconfig.rb +0 -260
  74. data/lib/cocoapods/generator/xcconfig/pod_xcconfig.rb +0 -87
  75. data/lib/cocoapods/generator/xcconfig/xcconfig_helper.rb +0 -558
@@ -38,6 +38,12 @@ module Pod
38
38
  File.chmod(0755, pathname.to_s)
39
39
  end
40
40
 
41
+ # @return [String] The contents of the copy resources script.
42
+ #
43
+ def generate
44
+ script
45
+ end
46
+
41
47
  private
42
48
 
43
49
  # @!group Private Helpers
@@ -8,13 +8,22 @@ module Pod
8
8
  @class_name = "PodsDummy_#{validated_class_name_identifier}"
9
9
  end
10
10
 
11
+ # @return [String] the string contents of the dummy source file.
12
+ #
13
+ def generate
14
+ result = <<-source.strip_heredoc
15
+ #import <Foundation/Foundation.h>
16
+ @interface #{class_name} : NSObject
17
+ @end
18
+ @implementation #{class_name}
19
+ @end
20
+ source
21
+ result
22
+ end
23
+
11
24
  def save_as(pathname)
12
25
  pathname.open('w') do |source|
13
- source.puts '#import <Foundation/Foundation.h>'
14
- source.puts "@interface #{class_name} : NSObject"
15
- source.puts '@end'
16
- source.puts "@implementation #{class_name}"
17
- source.puts '@end'
26
+ source.write(generate)
18
27
  end
19
28
  end
20
29
  end
@@ -27,6 +27,12 @@ module Pod
27
27
  File.chmod(0755, pathname.to_s)
28
28
  end
29
29
 
30
+ # @return [String] The contents of the embed frameworks script.
31
+ #
32
+ def generate
33
+ script
34
+ end
35
+
30
36
  private
31
37
 
32
38
  # @!group Private Helpers
@@ -84,8 +90,13 @@ module Pod
84
90
  local basename
85
91
  basename="$(basename -s .framework "$1")"
86
92
  binary="${destination}/${basename}.framework/${basename}"
93
+
87
94
  if ! [ -r "$binary" ]; then
88
95
  binary="${destination}/${basename}"
96
+ elif [ -L "${binary}" ]; then
97
+ echo "Destination binary is symlinked..."
98
+ dirname="$(dirname "${binary}")"
99
+ binary="${dirname}/$(readlink "${binary}")"
89
100
  fi
90
101
 
91
102
  # Strip invalid architectures so "fat" simulator / device frameworks work on device
@@ -138,8 +149,8 @@ module Pod
138
149
 
139
150
  # Signs a framework with the provided identity
140
151
  code_sign_if_enabled() {
141
- if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
142
- # Use the current code_sign_identitiy
152
+ if [ -n "${EXPANDED_CODE_SIGN_IDENTITY:-}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
153
+ # Use the current code_sign_identity
143
154
  echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
144
155
  local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
145
156
 
@@ -17,7 +17,7 @@ module Pod
17
17
 
18
18
  # @return [Array<String>] The list of the modules to import.
19
19
  #
20
- attr_accessor :module_imports
20
+ attr_reader :module_imports
21
21
 
22
22
  # Initialize a new instance
23
23
  #
@@ -18,16 +18,22 @@ module Pod
18
18
  #
19
19
  attr_reader :bundle_package_type
20
20
 
21
+ # @return [Hash] any additional entries to include in this Info.plist
22
+ #
23
+ attr_reader :additional_entries
24
+
21
25
  # Initialize a new instance
22
26
  #
23
- # @param [Version] version @see version
24
- # @param [Platform] platform @see platform
25
- # @param [Symbol] bundle_package_type @see bundle_package_type
27
+ # @param [Version] version @see #version
28
+ # @param [Platform] platform @see #platform
29
+ # @param [Symbol] bundle_package_type @see #bundle_package_type
30
+ # @param [Hash] additional_entries @see #additional_entries
26
31
  #
27
- def initialize(version, platform, bundle_package_type = :fmwk)
32
+ def initialize(version, platform, bundle_package_type = :fmwk, additional_entries = {})
28
33
  @version = version
29
34
  @platform = platform
30
35
  @bundle_package_type = bundle_package_type
36
+ @additional_entries = additional_entries
31
37
  end
32
38
 
33
39
  # Generates and saves the Info.plist to the given path.
@@ -109,6 +115,8 @@ module Pod
109
115
  info['CFBundleVersion'] = '1' if bundle_package_type == :bndl
110
116
  info['NSPrincipalClass'] = 'NSApplication' if bundle_package_type == :appl && platform == :osx
111
117
 
118
+ info.merge!(additional_entries)
119
+
112
120
  info
113
121
  end
114
122
  end
@@ -15,10 +15,10 @@ module Pod
15
15
  # Initialize a new instance
16
16
  #
17
17
  # @param [Array<FileAccessor>] file_accessors
18
- # @see file_accessors
18
+ # @see #file_accessors
19
19
  #
20
20
  # @param [Platform] platform
21
- # @see platform
21
+ # @see Header#platform
22
22
  #
23
23
  def initialize(file_accessors, platform)
24
24
  @file_accessors = file_accessors
@@ -76,6 +76,20 @@ module Pod
76
76
  @registrations[hook_name] << Hook.new(hook_name, plugin_name, block)
77
77
  end
78
78
 
79
+ # Returns all the hooks to run for the given event name
80
+ # and set of whitelisted plugins
81
+ #
82
+ # @see #run
83
+ #
84
+ # @return [Array<Hook>] the hooks to run
85
+ #
86
+ def hooks_to_run(name, whitelisted_plugins = nil)
87
+ return [] unless registrations
88
+ hooks = registrations.fetch(name, [])
89
+ return hooks unless whitelisted_plugins
90
+ hooks.select { |hook| whitelisted_plugins.key?(hook.plugin_name) }
91
+ end
92
+
79
93
  # Runs all the registered blocks for the hook with the given name.
80
94
  #
81
95
  # @param [Symbol] name
@@ -94,23 +108,20 @@ module Pod
94
108
  raise ArgumentError, 'Missing name' unless name
95
109
  raise ArgumentError, 'Missing options' unless context
96
110
 
97
- if registrations
98
- hooks = registrations[name]
99
- if hooks
100
- UI.message "- Running #{name.to_s.tr('_', ' ')} hooks" do
101
- hooks.each do |hook|
102
- next if whitelisted_plugins && !whitelisted_plugins.key?(hook.plugin_name)
103
- UI.message "- #{hook.plugin_name} from " \
104
- "`#{hook.block.source_location.first}`" do
105
- block = hook.block
106
- if block.arity > 1
107
- user_options = whitelisted_plugins[hook.plugin_name]
108
- user_options = user_options.with_indifferent_access if user_options
109
- block.call(context, user_options)
110
- else
111
- block.call(context)
112
- end
113
- end
111
+ hooks = hooks_to_run(name, whitelisted_plugins)
112
+ return if hooks.empty?
113
+
114
+ UI.message "- Running #{name.to_s.tr('_', ' ')} hooks" do
115
+ hooks.each do |hook|
116
+ UI.message "- #{hook.plugin_name} from " \
117
+ "`#{hook.block.source_location.first}`" do
118
+ block = hook.block
119
+ if block.arity > 1
120
+ user_options = whitelisted_plugins[hook.plugin_name]
121
+ user_options = user_options.with_indifferent_access if user_options
122
+ block.call(context, user_options)
123
+ else
124
+ block.call(context)
114
125
  end
115
126
  end
116
127
  end
@@ -61,13 +61,13 @@ module Pod
61
61
 
62
62
  # Initialize a new instance
63
63
  #
64
- # @param [Sandbox] sandbox @see sandbox
65
- # @param [Podfile] podfile @see podfile
66
- # @param [Lockfile] lockfile @see lockfile
64
+ # @param [Sandbox] sandbox @see #sandbox
65
+ # @param [Podfile] podfile @see #podfile
66
+ # @param [Lockfile] lockfile @see #lockfile
67
67
  #
68
68
  def initialize(sandbox, podfile, lockfile = nil)
69
- @sandbox = sandbox
70
- @podfile = podfile
69
+ @sandbox = sandbox || raise(ArgumentError, 'Missing required argument `sandbox`')
70
+ @podfile = podfile || raise(ArgumentError, 'Missing required argument `podfile`')
71
71
  @lockfile = lockfile
72
72
 
73
73
  @use_default_plugins = true
@@ -97,6 +97,12 @@ module Pod
97
97
  attr_accessor :use_default_plugins
98
98
  alias_method :use_default_plugins?, :use_default_plugins
99
99
 
100
+ # @return [Boolean] Whether installation should verify that there are no
101
+ # Podfile or Lockfile changes. Defaults to false.
102
+ #
103
+ attr_accessor :deployment
104
+ alias_method :deployment?, :deployment
105
+
100
106
  # Installs the Pods.
101
107
  #
102
108
  # The installation process is mostly linear with a few minor complications
@@ -155,12 +161,17 @@ module Pod
155
161
  validate_build_configurations
156
162
  clean_sandbox
157
163
  end
164
+
165
+ UI.section 'Verifying no changes' do
166
+ verify_no_podfile_changes!
167
+ verify_no_lockfile_changes!
168
+ end if deployment?
169
+
158
170
  analyzer
159
171
  end
160
172
 
161
173
  def download_dependencies
162
174
  UI.section 'Downloading dependencies' do
163
- create_file_accessors
164
175
  install_pod_sources
165
176
  run_podfile_pre_install_hooks
166
177
  clean_pod_sources
@@ -174,14 +185,14 @@ module Pod
174
185
  private
175
186
 
176
187
  def create_generator
177
- Xcode::PodsProjectGenerator.new(aggregate_targets, sandbox, pod_targets, analysis_result, installation_options, config)
188
+ Xcode::PodsProjectGenerator.new(sandbox, aggregate_targets, pod_targets, analysis_result, installation_options, config)
178
189
  end
179
190
 
180
191
  # Generate the 'Pods/Pods.xcodeproj' project.
181
192
  #
182
193
  def generate_pods_project(generator = create_generator)
183
194
  UI.section 'Generating Pods project' do
184
- generator.generate!
195
+ @target_installation_results = generator.generate!
185
196
  @pods_project = generator.project
186
197
  run_podfile_post_install_hooks
187
198
  generator.write
@@ -201,13 +212,14 @@ module Pod
201
212
  #
202
213
  attr_reader :analysis_result
203
214
 
204
- # @return [Pod::Project] the `Pods/Pods.xcodeproj` project.
215
+ # @return [Array<Hash{String, TargetInstallationResult}>] the installation results produced by the pods project
216
+ # generator
205
217
  #
206
- attr_reader :pods_project
218
+ attr_reader :target_installation_results
207
219
 
208
- # @return [Array<String>] The Pods that should be installed.
220
+ # @return [Pod::Project] the `Pods/Pods.xcodeproj` project.
209
221
  #
210
- attr_reader :names_of_pods_to_install
222
+ attr_reader :pods_project
211
223
 
212
224
  # @return [Array<AggregateTarget>] The model representations of an
213
225
  # aggregation of pod targets generated for a target definition
@@ -218,13 +230,9 @@ module Pod
218
230
  # @return [Array<PodTarget>] The model representations of pod targets
219
231
  # generated as result of the analyzer.
220
232
  #
221
- def pod_targets
222
- aggregate_target_pod_targets = aggregate_targets.flat_map(&:pod_targets)
223
- test_dependent_targets = aggregate_target_pod_targets.flat_map(&:test_dependent_targets)
224
- (aggregate_target_pod_targets + test_dependent_targets).uniq
225
- end
233
+ attr_reader :pod_targets
226
234
 
227
- # @return [Array<Specification>] The specifications that where installed.
235
+ # @return [Array<Specification>] The specifications that were installed.
228
236
  #
229
237
  attr_accessor :installed_specs
230
238
 
@@ -239,15 +247,14 @@ module Pod
239
247
  # @return [void]
240
248
  #
241
249
  def analyze(analyzer = create_analyzer)
242
- analyzer.update = update
243
250
  @analysis_result = analyzer.analyze
244
- @aggregate_targets = analyzer.result.targets
251
+ @aggregate_targets = @analysis_result.targets
252
+ @pod_targets = @analysis_result.pod_targets
245
253
  end
246
254
 
247
255
  def create_analyzer(plugin_sources = nil)
248
- Analyzer.new(sandbox, podfile, lockfile, plugin_sources).tap do |analyzer|
256
+ Analyzer.new(sandbox, podfile, lockfile, plugin_sources, has_dependencies?, update).tap do |analyzer|
249
257
  analyzer.installation_options = installation_options
250
- analyzer.has_dependencies = has_dependencies?
251
258
  end
252
259
  end
253
260
 
@@ -302,11 +309,26 @@ module Pod
302
309
  end
303
310
  end
304
311
 
305
- # @return [void] In this step we create the file accessors for the pod
306
- # targets.
312
+ # @raise [Informative] If there are any Podfile changes
307
313
  #
308
- def create_file_accessors
309
- sandbox.create_file_accessors(pod_targets)
314
+ def verify_no_podfile_changes!
315
+ return unless analysis_result.podfile_needs_install?
316
+
317
+ changed_state = analysis_result.podfile_state.to_s(:states => %i(added deleted changed))
318
+ raise Informative, "There were changes to the podfile in deployment mode:\n#{changed_state}"
319
+ end
320
+
321
+ # @raise [Informative] If there are any Lockfile changes
322
+ #
323
+ def verify_no_lockfile_changes!
324
+ new_lockfile = generate_lockfile
325
+ return if new_lockfile == lockfile
326
+
327
+ diff = Xcodeproj::Differ.hash_diff(lockfile.to_hash, new_lockfile.to_hash, :key_1 => 'Old Lockfile', :key_2 => 'New Lockfile')
328
+ pretty_diff = YAMLHelper.convert_hash(diff, Lockfile::HASH_KEY_ORDER, "\n\n")
329
+ pretty_diff.gsub!(':diff:', 'diff:'.yellow)
330
+
331
+ raise Informative, "There were changes to the lockfile in deployment mode:\n#{pretty_diff}"
310
332
  end
311
333
 
312
334
  # Downloads, installs the documentation and cleans the sources of the Pods
@@ -327,7 +349,7 @@ module Pod
327
349
  current_repo = analysis_result.specs_by_source.detect { |key, values| break key if values.map(&:name).include?(spec.name) }
328
350
  current_repo &&= current_repo.url || current_repo.name
329
351
  previous_spec_repo = sandbox.manifest.spec_repo(spec.name)
330
- has_changed_repo = !previous_spec_repo.nil? && current_repo && (current_repo != previous_spec_repo)
352
+ has_changed_repo = !previous_spec_repo.nil? && current_repo && !current_repo.casecmp(previous_spec_repo).zero?
331
353
  title = "Installing #{spec.name} #{spec.version}"
332
354
  title << " (was #{previous_version} and source changed to `#{current_repo}` from `#{previous_spec_repo}`)" if has_changed_version && has_changed_repo
333
355
  title << " (was #{previous_version})" if has_changed_version && !has_changed_repo
@@ -355,7 +377,13 @@ module Pod
355
377
  end
356
378
  end
357
379
 
358
- raise Informative, "Could not install '#{pod_name}' pod. There is no target that supports it." if specs_by_platform.empty?
380
+ if specs_by_platform.empty?
381
+ requiring_targets = pod_targets.select { |pt| pt.recursive_dependent_targets.any? { |dt| dt.pod_name == pod_name } }
382
+ message = "Could not install '#{pod_name}' pod"
383
+ message += ", dependended upon by #{requiring_targets.to_sentence}" unless requiring_targets.empty?
384
+ message += '. There is either no platform to build for, or no target to build.'
385
+ raise StandardError, message
386
+ end
359
387
 
360
388
  @pod_installers ||= []
361
389
  pod_installer = PodSourceInstaller.new(sandbox, specs_by_platform, :can_cache => installation_options.clean?)
@@ -429,11 +457,9 @@ module Pod
429
457
  # @return [void]
430
458
  #
431
459
  def perform_post_install_actions
432
- unlock_pod_sources
433
460
  run_plugins_post_install_hooks
434
461
  warn_for_deprecations
435
462
  warn_for_installed_script_phases
436
- lock_pod_sources
437
463
  print_post_install_message
438
464
  end
439
465
 
@@ -451,8 +477,21 @@ module Pod
451
477
  # Runs the registered callbacks for the plugins post install hooks.
452
478
  #
453
479
  def run_plugins_post_install_hooks
454
- context = PostInstallHooksContext.generate(sandbox, aggregate_targets)
455
- HooksManager.run(:post_install, context, plugins)
480
+ # This short-circuits because unlocking pod sources is expensive
481
+ if any_plugin_post_install_hooks?
482
+ unlock_pod_sources
483
+
484
+ context = PostInstallHooksContext.generate(sandbox, aggregate_targets)
485
+ HooksManager.run(:post_install, context, plugins)
486
+ end
487
+
488
+ lock_pod_sources
489
+ end
490
+
491
+ # @return [Boolean] whether there are any plugin post-install hooks to run
492
+ #
493
+ def any_plugin_post_install_hooks?
494
+ HooksManager.hooks_to_run(:post_install, plugins).any?
456
495
  end
457
496
 
458
497
  # Runs the registered callbacks for the source provider plugin hooks.
@@ -550,16 +589,20 @@ module Pod
550
589
  end
551
590
  end
552
591
 
553
- # Writes the Podfile and the lock files.
592
+ # @return [Lockfile] The lockfile to write to disk.
554
593
  #
555
- # @todo Pass the checkout options to the Lockfile.
594
+ def generate_lockfile
595
+ external_source_pods = analysis_result.podfile_dependency_cache.podfile_dependencies.select(&:external_source).map(&:root_name).uniq
596
+ checkout_options = sandbox.checkout_sources.select { |root_name, _| external_source_pods.include? root_name }
597
+ Lockfile.generate(podfile, analysis_result.specifications, checkout_options, analysis_result.specs_by_source)
598
+ end
599
+
600
+ # Writes the Podfile and the lock files.
556
601
  #
557
602
  # @return [void]
558
603
  #
559
604
  def write_lockfiles
560
- external_source_pods = analysis_result.podfile_dependency_cache.podfile_dependencies.select(&:external_source).map(&:root_name).uniq
561
- checkout_options = sandbox.checkout_sources.select { |root_name, _| external_source_pods.include? root_name }
562
- @lockfile = Lockfile.generate(podfile, analysis_result.specifications, checkout_options, analysis_result.specs_by_source)
605
+ @lockfile = generate_lockfile
563
606
 
564
607
  UI.message "- Writing Lockfile in #{UI.path config.lockfile_path}" do
565
608
  @lockfile.write_to_disk(config.lockfile_path)
@@ -579,11 +622,6 @@ module Pod
579
622
  #
580
623
  # @return [void]
581
624
  #
582
- # @todo [#397] The libraries should be cleaned and the re-added on every
583
- # installation. Maybe a clean_user_project phase should be added.
584
- # In any case it appears to be a good idea store target definition
585
- # information in the lockfile.
586
- #
587
625
  def integrate_user_project
588
626
  UI.section "Integrating client #{'project'.pluralize(aggregate_targets.map(&:user_project_path).uniq.count)}" do
589
627
  installation_root = config.installation_root
@@ -684,5 +722,28 @@ module Pod
684
722
  end
685
723
 
686
724
  #-------------------------------------------------------------------------#
725
+
726
+ public
727
+
728
+ # @!group Convenience Methods
729
+
730
+ def self.targets_from_sandbox(sandbox, podfile, lockfile)
731
+ raise Informative, 'You must run `pod install` to be able to generate target information' unless lockfile
732
+
733
+ new(sandbox, podfile, lockfile).instance_exec do
734
+ plugin_sources = run_source_provider_hooks
735
+ analyzer = create_analyzer(plugin_sources)
736
+ analyze(analyzer)
737
+ if analysis_result.podfile_needs_install?
738
+ raise Pod::Informative, 'The Podfile has changed, you must run `pod install`'
739
+ elsif analysis_result.sandbox_needs_install?
740
+ raise Pod::Informative, 'The `Pods` directory is out-of-date, you must run `pod install`'
741
+ end
742
+
743
+ aggregate_targets
744
+ end
745
+ end
746
+
747
+ #-------------------------------------------------------------------------#
687
748
  end
688
749
  end