cocoapods 0.16.4 → 0.17.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +108 -0
  3. data/README.md +3 -3
  4. data/bin/pod +1 -1
  5. data/lib/cocoapods.rb +31 -31
  6. data/lib/cocoapods/command.rb +62 -107
  7. data/lib/cocoapods/command/inter_process_communication.rb +103 -0
  8. data/lib/cocoapods/command/list.rb +45 -44
  9. data/lib/cocoapods/command/outdated.rb +28 -25
  10. data/lib/cocoapods/command/project.rb +90 -0
  11. data/lib/cocoapods/command/push.rb +50 -32
  12. data/lib/cocoapods/command/repo.rb +125 -155
  13. data/lib/cocoapods/command/search.rb +23 -12
  14. data/lib/cocoapods/command/setup.rb +103 -64
  15. data/lib/cocoapods/command/spec.rb +329 -90
  16. data/lib/cocoapods/config.rb +197 -44
  17. data/lib/cocoapods/downloader.rb +47 -34
  18. data/lib/cocoapods/executable.rb +98 -41
  19. data/lib/cocoapods/external_sources.rb +325 -0
  20. data/lib/cocoapods/file_list.rb +8 -1
  21. data/lib/cocoapods/gem_version.rb +7 -0
  22. data/lib/cocoapods/generator/acknowledgements.rb +71 -7
  23. data/lib/cocoapods/generator/acknowledgements/markdown.rb +10 -9
  24. data/lib/cocoapods/generator/acknowledgements/plist.rb +9 -8
  25. data/lib/cocoapods/generator/copy_resources_script.rb +2 -2
  26. data/lib/cocoapods/generator/documentation.rb +153 -37
  27. data/lib/cocoapods/generator/prefix_header.rb +82 -0
  28. data/lib/cocoapods/generator/target_header.rb +58 -0
  29. data/lib/cocoapods/generator/xcconfig.rb +130 -0
  30. data/lib/cocoapods/hooks/installer_representation.rb +123 -0
  31. data/lib/cocoapods/hooks/library_representation.rb +79 -0
  32. data/lib/cocoapods/hooks/pod_representation.rb +74 -0
  33. data/lib/cocoapods/installer.rb +398 -147
  34. data/lib/cocoapods/installer/analyzer.rb +556 -0
  35. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +253 -0
  36. data/lib/cocoapods/installer/file_references_installer.rb +179 -0
  37. data/lib/cocoapods/installer/pod_source_installer.rb +289 -0
  38. data/lib/cocoapods/installer/target_installer.rb +307 -112
  39. data/lib/cocoapods/installer/user_project_integrator.rb +140 -176
  40. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +193 -0
  41. data/lib/cocoapods/library.rb +195 -0
  42. data/lib/cocoapods/open_uri.rb +16 -14
  43. data/lib/cocoapods/project.rb +175 -52
  44. data/lib/cocoapods/resolver.rb +151 -164
  45. data/lib/cocoapods/sandbox.rb +276 -54
  46. data/lib/cocoapods/sandbox/file_accessor.rb +210 -0
  47. data/lib/cocoapods/sandbox/headers_store.rb +96 -0
  48. data/lib/cocoapods/sandbox/path_list.rb +178 -0
  49. data/lib/cocoapods/sources_manager.rb +218 -0
  50. data/lib/cocoapods/user_interface.rb +82 -18
  51. data/lib/cocoapods/{command → user_interface}/error_report.rb +5 -5
  52. data/lib/cocoapods/validator.rb +379 -0
  53. metadata +74 -55
  54. data/lib/cocoapods/command/install.rb +0 -55
  55. data/lib/cocoapods/command/linter.rb +0 -317
  56. data/lib/cocoapods/command/update.rb +0 -25
  57. data/lib/cocoapods/dependency.rb +0 -285
  58. data/lib/cocoapods/downloader/git.rb +0 -276
  59. data/lib/cocoapods/downloader/http.rb +0 -99
  60. data/lib/cocoapods/downloader/mercurial.rb +0 -26
  61. data/lib/cocoapods/downloader/subversion.rb +0 -42
  62. data/lib/cocoapods/local_pod.rb +0 -620
  63. data/lib/cocoapods/lockfile.rb +0 -274
  64. data/lib/cocoapods/platform.rb +0 -127
  65. data/lib/cocoapods/podfile.rb +0 -551
  66. data/lib/cocoapods/source.rb +0 -223
  67. data/lib/cocoapods/specification.rb +0 -579
  68. data/lib/cocoapods/specification/set.rb +0 -175
  69. data/lib/cocoapods/specification/statistics.rb +0 -112
  70. data/lib/cocoapods/user_interface/ui_pod.rb +0 -130
  71. data/lib/cocoapods/version.rb +0 -26
@@ -0,0 +1,253 @@
1
+ module Pod
2
+ class Installer
3
+ class Analyzer
4
+
5
+ # Analyze the sandbox to detect which Pods should be removed, and which
6
+ # ones should be reinstalled.
7
+ #
8
+ # The logic is the following:
9
+ #
10
+ # Added
11
+ # - If not present in the sandbox lockfile.
12
+ # - The directory of the Pod doesn't exits.
13
+ #
14
+ # Changed
15
+ # - The version of the Pod changed.
16
+ # - The SHA of the specification file changed.
17
+ # - The specific installed (sub)specs of the same Pod changed.
18
+ # - The specification is in head mode or from an external source and the
19
+ # installation process is in update mode.
20
+ # - The directory of the Pod is empty.
21
+ # - The Pod has been pre-downloaded.
22
+ #
23
+ # Removed
24
+ # - If a specification is present in the lockfile but not in the resolved
25
+ # specs.
26
+ #
27
+ # Unchanged
28
+ # - If none of the above conditions match.
29
+ #
30
+ class SandboxAnalyzer
31
+
32
+ # @return [Sandbox] The sandbox to analyze.
33
+ #
34
+ attr_reader :sandbox
35
+
36
+ # @return [Array<Specifications>] The specifications returned by the
37
+ # resolver.
38
+ #
39
+ attr_reader :specs
40
+
41
+ # @return [Bool] Whether the installation is performed in update mode.
42
+ #
43
+ attr_reader :update_mode
44
+
45
+ # @return [Lockfile] The lockfile of the installation as a fall-back if
46
+ # there is no sandbox manifest. This is indented as a temporary
47
+ # solution to prevent the full re-installation from users which
48
+ # are upgrading from CP < 0.17.
49
+ #
50
+ # @todo Remove for CP 0.18.
51
+ #
52
+ attr_reader :lockfile
53
+
54
+ # @param [Sandbox] sandbox @see sandbox
55
+ # @param [Array<Specifications>] specs @see specs
56
+ # @param [Bool] update_mode @see update_mode
57
+ # @param [Lockfile] lockfile @see lockfile
58
+ #
59
+ def initialize(sandbox, specs, update_mode, lockfile = nil)
60
+ @sandbox = sandbox
61
+ @specs = specs
62
+ @update_mode = update_mode
63
+ @lockfile = lockfile
64
+ end
65
+
66
+ # Performs the analysis to the detect the state of the sandbox respect
67
+ # to the resolved specifications.
68
+ #
69
+ # @return [SpecsState] the state of the sandbox.
70
+ #
71
+ def analyze
72
+ state = SpecsState.new
73
+ if sandbox_manifest
74
+ all_names = (resolved_pods + sandbox_pods).uniq.sort
75
+ all_names.sort.each do |name|
76
+ state.add_name(name, pod_state(name))
77
+ end
78
+ else
79
+ state.added.concat(resolved_pods)
80
+ end
81
+ state
82
+ end
83
+
84
+ #---------------------------------------------------------------------#
85
+
86
+ private
87
+
88
+ # @!group Pod state
89
+
90
+ # Returns the state of the Pod with the given name.
91
+ #
92
+ # @param [String] pod
93
+ # the name of the Pod.
94
+ #
95
+ # @return [Symbol] The state
96
+ #
97
+ def pod_state(pod)
98
+ return :added if pod_added?(pod)
99
+ return :deleted if pod_deleted?(pod)
100
+ return :changed if pod_changed?(pod)
101
+ return :unchanged
102
+ end
103
+
104
+ # Returns whether the Pod with the given name should be installed.
105
+ #
106
+ # @note A Pod whose folder doesn't exists is considered added.
107
+ #
108
+ # @param [String] pod
109
+ # the name of the Pod.
110
+ #
111
+ # @return [Bool] Whether the Pod is added.
112
+ #
113
+ def pod_added?(pod)
114
+ return true if resolved_pods.include?(pod) && !sandbox_pods.include?(pod)
115
+ return true if !folder_exist?(pod)
116
+ return false
117
+ end
118
+
119
+ # Returns whether the Pod with the given name should be removed from
120
+ # the installation.
121
+ #
122
+ # @param [String] pod
123
+ # the name of the Pod.
124
+ #
125
+ # @return [Bool] Whether the Pod is deleted.
126
+ #
127
+ def pod_deleted?(pod)
128
+ return true if !resolved_pods.include?(pod) && sandbox_pods.include?(pod)
129
+ return false
130
+ end
131
+
132
+ # Returns whether the Pod with the given name should be considered
133
+ # changed and thus should be reinstalled.
134
+ #
135
+ # @note In update mode, as there is no way to know if a remote source
136
+ # hash changed the Pods in head mode and the ones from external
137
+ # sources are always marked as changed.
138
+ #
139
+ # @note A Pod whose folder is empty is considered changed.
140
+ #
141
+ # @param [String] pod
142
+ # the name of the Pod.
143
+ #
144
+ # @return [Bool] Whether the Pod is changed.
145
+ #
146
+ def pod_changed?(pod)
147
+ spec = root_spec(pod)
148
+ return true if spec.version != sandbox_version(pod)
149
+ return true if spec.checksum != sandbox_checksum(pod)
150
+ return true if resolved_spec_names(pod) != sandbox_spec_names(pod)
151
+ return true if sandbox.predownloaded?(pod)
152
+ return true if folder_empty?(pod)
153
+ if update_mode
154
+ return true if spec.version.head?
155
+ end
156
+ return false
157
+ end
158
+
159
+ #---------------------------------------------------------------------#
160
+
161
+ private
162
+
163
+ # @!group Private helpers
164
+
165
+ # @return [Lockfile] The manifest to use for the sandbox.
166
+ #
167
+ def sandbox_manifest
168
+ sandbox.manifest || lockfile
169
+ end
170
+
171
+ #--------------------------------------#
172
+
173
+ # @return [Array<String>] The name of the resolved Pods.
174
+ #
175
+ def resolved_pods
176
+ specs.map { |spec| spec.root.name }.uniq
177
+ end
178
+
179
+ # @return [Array<String>] The name of the Pods stored in the sandbox
180
+ # manifest.
181
+ #
182
+ def sandbox_pods
183
+ sandbox_manifest.pod_names.map { |name| Specification.root_name(name) }.uniq
184
+ end
185
+
186
+ # @return [Array<String>] The name of the resolved specifications
187
+ # (includes subspecs).
188
+ #
189
+ # @param [String] pod
190
+ # the name of the Pod.
191
+ #
192
+ def resolved_spec_names(pod)
193
+ specs.select { |s| s.root.name == pod }.map(&:name).uniq
194
+ end
195
+
196
+ # @return [Array<String>] The name of the specifications stored in the
197
+ # sandbox manifest (includes subspecs).
198
+ #
199
+ # @param [String] pod
200
+ # the name of the Pod.
201
+ #
202
+ def sandbox_spec_names(pod)
203
+ sandbox_manifest.pod_names.select { |name| Specification.root_name(name) == pod }.uniq
204
+ end
205
+
206
+ # @return [Specification] The root specification for the Pod with the
207
+ # given name.
208
+ #
209
+ # @param [String] pod
210
+ # the name of the Pod.
211
+ #
212
+ def root_spec(pod)
213
+ specs.find { |s| s.root.name == pod }.root
214
+ end
215
+
216
+ #--------------------------------------#
217
+
218
+ # @return [Version] The version of Pod with the given name stored in
219
+ # the sandbox.
220
+ #
221
+ # @param [String] pod
222
+ # the name of the Pod.
223
+ #
224
+ def sandbox_version(pod)
225
+ sandbox_manifest.version(pod)
226
+ end
227
+
228
+ # @return [String] The checksum of the specification of the Pod with
229
+ # the given name stored in the sandbox.
230
+ #
231
+ # @param [String] pod
232
+ # the name of the Pod.
233
+ #
234
+ def sandbox_checksum(pod)
235
+ sandbox_manifest.checksum(pod)
236
+ end
237
+
238
+ #--------------------------------------#
239
+
240
+ def folder_exist?(pod)
241
+ sandbox.pod_dir(pod).exist?
242
+ end
243
+
244
+ def folder_empty?(pod)
245
+ Dir.glob(sandbox.pod_dir(pod) + '*').empty?
246
+ end
247
+
248
+ #---------------------------------------------------------------------#
249
+
250
+ end
251
+ end
252
+ end
253
+ end
@@ -0,0 +1,179 @@
1
+ module Pod
2
+ class Installer
3
+
4
+ # Controller class responsible of installing the file references of the
5
+ # specifications in the Pods project.
6
+ #
7
+ class FileReferencesInstaller
8
+
9
+ # @return [Sandbox] The sandbox of the installation.
10
+ #
11
+ attr_reader :sandbox
12
+
13
+ # @return [Array<Library>] The libraries of the installation.
14
+ #
15
+ attr_reader :libraries
16
+
17
+ # @return [Project] The Pods project.
18
+ #
19
+ attr_reader :pods_project
20
+
21
+ # @param [Sandbox] sandbox @see sandbox
22
+ # @param [Array<Library>] libraries @see libraries
23
+ # @param [Project] libraries @see libraries
24
+ #
25
+ def initialize(sandbox, libraries, pods_project)
26
+ @sandbox = sandbox
27
+ @libraries = libraries
28
+ @pods_project = pods_project
29
+ end
30
+
31
+ # Installs the file references.
32
+ #
33
+ # @return [void]
34
+ #
35
+ def install!
36
+ refresh_file_accessors
37
+ add_source_files_references
38
+ add_resources_references
39
+ link_headers
40
+ end
41
+
42
+ #-----------------------------------------------------------------------#
43
+
44
+ private
45
+
46
+ # @!group Installation Steps
47
+
48
+ # Reads the file accessors contents from the file system.
49
+ #
50
+ # @note The contents of the file accessors are modified by the clean
51
+ # step of the #{PodSourceInstaller} and by the pre install hooks.
52
+ #
53
+ # @return [void]
54
+ #
55
+ def refresh_file_accessors
56
+ file_accessors.each do |fa|
57
+ fa.path_list.read_file_system
58
+ end
59
+ end
60
+
61
+ # Adds the source files of the Pods to the Pods project.
62
+ #
63
+ # @note The source files are grouped by Pod and in turn by subspec
64
+ # (recursively).
65
+ #
66
+ # @note Pods are generally added to the `Pods` group, however, if they
67
+ # have a local source they are added to the
68
+ # `Local Pods` group.
69
+ #
70
+ # @return [void]
71
+ #
72
+ def add_source_files_references
73
+ UI.message "- Adding source files to Pods project" do
74
+ file_accessors.each do |file_accessor|
75
+ files = file_accessor.source_files
76
+ spec_name = file_accessor.spec.name
77
+ local = sandbox.local?(file_accessor.spec.root.name)
78
+ parent_group = local ? pods_project.local_pods : pods_project.pods
79
+ pods_project.add_file_references(files, spec_name, parent_group)
80
+ end
81
+ end
82
+ end
83
+
84
+ # Adds the resources of the Pods to the Pods project.
85
+ #
86
+ # @note The source files are grouped by Pod and in turn by subspec
87
+ # (recursively) in the resources group.
88
+ #
89
+ # @return [void]
90
+ #
91
+ def add_resources_references
92
+ UI.message "- Adding resources to Pods project" do
93
+ file_accessors.each do |file_accessor|
94
+ file_accessor.resources.each do |resources|
95
+ files = file_accessor.resources
96
+ spec_name = file_accessor.spec.name
97
+ parent_group = pods_project.resources
98
+ pods_project.add_file_references(files, spec_name, parent_group)
99
+ end
100
+ end
101
+ end
102
+ end
103
+
104
+ # Creates the link to the headers of the Pod in the sandbox.
105
+ #
106
+ # @return [void]
107
+ #
108
+ def link_headers
109
+ UI.message "- Linking headers" do
110
+
111
+ file_accessors.each do |file_accessor|
112
+ headers_sandbox = Pathname.new(file_accessor.spec.root.name)
113
+ sandbox.build_headers.add_search_path(headers_sandbox)
114
+ sandbox.public_headers.add_search_path(headers_sandbox)
115
+
116
+ consumer = file_accessor.spec_consumer
117
+ header_mappings(headers_sandbox, consumer, file_accessor.headers).each do |namespaced_path, files|
118
+ sandbox.build_headers.add_files(namespaced_path, files)
119
+ end
120
+
121
+ header_mappings(headers_sandbox, consumer, file_accessor.public_headers).each do |namespaced_path, files|
122
+ sandbox.public_headers.add_files(namespaced_path, files)
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ #-----------------------------------------------------------------------#
129
+
130
+ private
131
+
132
+ # @!group Private Helpers
133
+
134
+ # @return [Array<Sandbox::FileAccessor>] The file accessors for all the
135
+ # specs platform combinations.
136
+ #
137
+ def file_accessors
138
+ @file_accessors ||= libraries.map(&:file_accessors).flatten.compact
139
+ end
140
+
141
+ # Computes the destination sub-directory in the sandbox
142
+ #
143
+ # @param [Pathname] headers_sandbox
144
+ # The sandbox where the headers links should be stored for this
145
+ # Pod.
146
+ #
147
+ # @param [Specification::Consumer] consumer
148
+ # The consumer for which the headers need to be linked.
149
+ #
150
+ # @param [Array<Pathname>] headers
151
+ # The absolute paths of the headers which need to be mapped.
152
+ #
153
+ # @return [Hash{Pathname => Array<Pathname>}] A hash containing the
154
+ # headers folders as the keys and the absolute paths of the
155
+ # header files as the values.
156
+ #
157
+ def header_mappings(headers_sandbox, consumer, headers)
158
+ dir = headers_sandbox
159
+ dir = dir + consumer.header_dir if consumer.header_dir
160
+
161
+ mappings = {}
162
+ headers.each do |header|
163
+ sub_dir = dir
164
+ if consumer.header_mappings_dir
165
+ header_mappings_dir = Pathname.new(consumer.header_mappings_dir)
166
+ relative_path = header.relative_path_from(header_mappings_dir)
167
+ sub_dir = sub_dir + relative_path.dirname
168
+ end
169
+ mappings[sub_dir] ||= []
170
+ mappings[sub_dir] << header
171
+ end
172
+ mappings
173
+ end
174
+
175
+ #-----------------------------------------------------------------------#
176
+
177
+ end
178
+ end
179
+ end
@@ -0,0 +1,289 @@
1
+ module Pod
2
+ class Installer
3
+
4
+ # Controller class responsible of installing the activated specifications
5
+ # of a single Pod.
6
+ #
7
+ # @note This class needs to consider all the activated specs of a Pod.
8
+ #
9
+ class PodSourceInstaller
10
+
11
+ # @return [Sandbox]
12
+ #
13
+ attr_reader :sandbox
14
+
15
+ # @return [Hash{Symbol=>Array}] The specifications that need to be
16
+ # installed grouped by platform.
17
+ #
18
+ attr_reader :specs_by_platform
19
+
20
+ # @param [Sandbox] sandbox @see sandbox
21
+ # @param [Hash{Symbol=>Array}] specs_by_platform @see specs_by_platform
22
+ #
23
+ def initialize(sandbox, specs_by_platform)
24
+ @sandbox = sandbox
25
+ @specs_by_platform = specs_by_platform
26
+
27
+ @clean = true
28
+ @generate_docs = false
29
+ @install_docs = false
30
+ @aggressive_cache = false
31
+ end
32
+
33
+ # @return [String] A string suitable for debugging.
34
+ #
35
+ def inspect
36
+ "<#{self.class} sandbox=#{sandbox.root} pod=#{root_spec.name}"
37
+ end
38
+
39
+ #-----------------------------------------------------------------------#
40
+
41
+ public
42
+
43
+ # @!group Configuration
44
+
45
+ # @return [Bool] whether the file not used by CocoaPods should be
46
+ # removed.
47
+ #
48
+ attr_accessor :clean
49
+ alias_method :clean?, :clean
50
+
51
+ # @return [Bool] whether the documentation should be generated for the
52
+ # Pod.
53
+ #
54
+ attr_accessor :generate_docs
55
+ alias_method :generate_docs?, :generate_docs
56
+
57
+ # @return [Bool] whether the generated documentation should be installed
58
+ # in Xcode.
59
+ #
60
+ attr_accessor :install_docs
61
+ alias_method :install_docs?, :install_docs
62
+
63
+ # @return [Bool] whether the downloader should always check against the
64
+ # remote if issues might be generated (mostly useful to speed up
65
+ # testing).
66
+ #
67
+ # @note This might be removed in future.
68
+ #
69
+ attr_accessor :aggressive_cache
70
+ alias_method :aggressive_cache?, :aggressive_cache
71
+
72
+ #-----------------------------------------------------------------------#
73
+
74
+ public
75
+
76
+ # @!group Installation
77
+
78
+ # Creates the target in the Pods project and the relative support files.
79
+ #
80
+ # @return [void]
81
+ #
82
+ def install!
83
+ download_source unless predownloaded? || local?
84
+ generate_docs if generate_docs?
85
+ clean_installation if clean? && !local?
86
+ end
87
+
88
+ # @return [Hash]
89
+ #
90
+ attr_reader :specific_source
91
+
92
+ #-----------------------------------------------------------------------#
93
+
94
+ private
95
+
96
+ # @!group Installation Steps
97
+
98
+ # Downloads the source of the Pod. It also stores the specific options
99
+ # needed to recreate the same exact installation if needed in
100
+ # `#specific_source`.
101
+ #
102
+ # @return [void]
103
+ #
104
+ def download_source
105
+ root.rmtree if root.exist?
106
+ if root_spec.version.head?
107
+ downloader.download_head
108
+ @specific_source = downloader.checkout_options
109
+ else
110
+ downloader.download
111
+ unless downloader.options_specific?
112
+ @specific_source = downloader.checkout_options
113
+ end
114
+ end
115
+
116
+ if specific_source
117
+ sandbox.store_checkout_source(root_spec.name, specific_source)
118
+ end
119
+ end
120
+
121
+ # Generates the documentation for the Pod.
122
+ #
123
+ # @return [void]
124
+ #
125
+ def generate_docs
126
+ if @cleaned
127
+ raise Informative, "Attempt to generate the documentation from a cleaned Pod."
128
+ end
129
+
130
+ if documentation_generator.already_installed?
131
+ UI.section " > Using existing documentation"
132
+ else
133
+ UI.section " > Installing documentation" do
134
+ documentation_generator.generate(install_docs?)
135
+ end
136
+ end
137
+ end
138
+
139
+ # Removes all the files not needed for the installation according to the
140
+ # specs by platform.
141
+ #
142
+ # @return [void]
143
+ #
144
+ def clean_installation
145
+ clean_paths.each { |path| FileUtils.rm_rf(path) }
146
+ @cleaned = true
147
+ end
148
+
149
+ #-----------------------------------------------------------------------#
150
+
151
+ public
152
+
153
+ # @!group Dependencies
154
+
155
+ # @return [String] The directory where CocoaPods caches the downloads.
156
+ #
157
+ CACHE_ROOT = "~/Library/Caches/CocoaPods"
158
+
159
+ # @return [Fixnum] The maximum size for the cache expressed in Mb.
160
+ #
161
+ MAX_CACHE_SIZE = 500
162
+
163
+ # @return [Downloader] The downloader to use for the retrieving the
164
+ # source.
165
+ #
166
+ def downloader
167
+ return @downloader if @downloader
168
+ @downloader = Downloader.for_target(root, root_spec.source.dup)
169
+ @downloader.cache_root = CACHE_ROOT
170
+ @downloader.max_cache_size = MAX_CACHE_SIZE
171
+ @downloader.aggressive_cache = aggressive_cache?
172
+ @downloader
173
+ end
174
+
175
+ # @return [Generator::Documentation] The documentation generator to use
176
+ # for generating the documentation.
177
+ #
178
+ def documentation_generator
179
+ @documentation_generator ||= Generator::Documentation.new(sandbox, root_spec, path_list)
180
+ end
181
+
182
+ #-----------------------------------------------------------------------#
183
+
184
+ private
185
+
186
+ # @!group Convenience methods.
187
+
188
+ # @return [Array<Specifications>] the specification of the Pod used in
189
+ # this installation.
190
+ #
191
+ def specs
192
+ specs_by_platform.values.flatten
193
+ end
194
+
195
+ # @return [Specification] the root specification of the Pod.
196
+ #
197
+ def root_spec
198
+ specs.first.root
199
+ end
200
+
201
+ # @return [Pathname] the folder where the source of the Pod is located.
202
+ #
203
+ def root
204
+ sandbox.pod_dir(root_spec.name)
205
+ end
206
+
207
+ # @return [Boolean] whether the source has been pre downloaded in the
208
+ # resolution process to retrieve its podspec.
209
+ #
210
+ def predownloaded?
211
+ sandbox.predownloaded_pods.include?(root_spec.name)
212
+ end
213
+
214
+ # @return [Boolean] whether the pod uses the local option and thus
215
+ # CocoaPods should not interfere with the files of the user.
216
+ #
217
+ def local?
218
+ sandbox.local?(root_spec.name)
219
+ end
220
+
221
+ #-----------------------------------------------------------------------#
222
+
223
+ private
224
+
225
+ # @!group Private helpers
226
+
227
+ # @return [Array<Sandbox::FileAccessor>] the file accessors for all the
228
+ # specifications on their respective platform.
229
+ #
230
+ def file_accessors
231
+ return @file_accessors if @file_accessors
232
+ @file_accessors = []
233
+ specs_by_platform.each do |platform, specs|
234
+ specs.each do |spec|
235
+ @file_accessors << Sandbox::FileAccessor.new(path_list, spec.consumer(platform))
236
+ end
237
+ end
238
+ @file_accessors
239
+ end
240
+
241
+ # @return [Sandbox::PathList] The path list for this Pod.
242
+ #
243
+ def path_list
244
+ @path_list ||= Sandbox::PathList.new(root)
245
+ end
246
+
247
+ # Finds the absolute paths, including hidden ones, of the files
248
+ # that are not used by the pod and thus can be safely deleted.
249
+ #
250
+ # @note Implementation detail: Don't use `Dir#glob` as there is an
251
+ # unexplained issue (#568, #572 and #602).
252
+ #
253
+ # @return [Array<Strings>] The paths that can be deleted.
254
+ #
255
+ def clean_paths
256
+ cached_used = used_files
257
+ glob_options = File::FNM_DOTMATCH | File::FNM_CASEFOLD
258
+ files = Pathname.glob(root + "**/*", glob_options).map(&:to_s)
259
+
260
+ files.reject! do |candidate|
261
+ candidate.end_with?('.', '..') || cached_used.any? do |path|
262
+ path.include?(candidate) || candidate.include?(path)
263
+ end
264
+ end
265
+ files
266
+ end
267
+
268
+ # @return [Array<String>] The absolute path of all the files used by the
269
+ # specifications (according to their platform) of this Pod.
270
+ #
271
+ def used_files
272
+
273
+ files = [
274
+ file_accessors.map(&:source_files),
275
+ file_accessors.map(&:resources),
276
+ file_accessors.map(&:preserve_paths),
277
+ file_accessors.map(&:prefix_header),
278
+ file_accessors.map(&:readme),
279
+ file_accessors.map(&:license),
280
+ ]
281
+
282
+ files.flatten.compact.map{ |path| path.to_s }.uniq
283
+ end
284
+
285
+ #-----------------------------------------------------------------------#
286
+
287
+ end
288
+ end
289
+ end