cocoapods-core 0.17.0.rc1

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 (36) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +20 -0
  3. data/README.md +36 -0
  4. data/lib/cocoapods-core/core_ui.rb +19 -0
  5. data/lib/cocoapods-core/dependency.rb +295 -0
  6. data/lib/cocoapods-core/gem_version.rb +6 -0
  7. data/lib/cocoapods-core/lockfile.rb +440 -0
  8. data/lib/cocoapods-core/platform.rb +171 -0
  9. data/lib/cocoapods-core/podfile/dsl.rb +459 -0
  10. data/lib/cocoapods-core/podfile/target_definition.rb +503 -0
  11. data/lib/cocoapods-core/podfile.rb +345 -0
  12. data/lib/cocoapods-core/requirement.rb +15 -0
  13. data/lib/cocoapods-core/source/validator.rb +183 -0
  14. data/lib/cocoapods-core/source.rb +284 -0
  15. data/lib/cocoapods-core/specification/consumer.rb +356 -0
  16. data/lib/cocoapods-core/specification/dsl/attribute.rb +245 -0
  17. data/lib/cocoapods-core/specification/dsl/attribute_support.rb +76 -0
  18. data/lib/cocoapods-core/specification/dsl/deprecations.rb +47 -0
  19. data/lib/cocoapods-core/specification/dsl/platform_proxy.rb +67 -0
  20. data/lib/cocoapods-core/specification/dsl.rb +1110 -0
  21. data/lib/cocoapods-core/specification/linter.rb +436 -0
  22. data/lib/cocoapods-core/specification/root_attribute_accessors.rb +152 -0
  23. data/lib/cocoapods-core/specification/set/presenter.rb +229 -0
  24. data/lib/cocoapods-core/specification/set/statistics.rb +277 -0
  25. data/lib/cocoapods-core/specification/set.rb +171 -0
  26. data/lib/cocoapods-core/specification/yaml.rb +60 -0
  27. data/lib/cocoapods-core/specification.rb +592 -0
  28. data/lib/cocoapods-core/standard_error.rb +84 -0
  29. data/lib/cocoapods-core/vendor/dependency.rb +264 -0
  30. data/lib/cocoapods-core/vendor/requirement.rb +208 -0
  31. data/lib/cocoapods-core/vendor/version.rb +333 -0
  32. data/lib/cocoapods-core/vendor.rb +56 -0
  33. data/lib/cocoapods-core/version.rb +99 -0
  34. data/lib/cocoapods-core/yaml_converter.rb +202 -0
  35. data/lib/cocoapods-core.rb +23 -0
  36. metadata +154 -0
@@ -0,0 +1,284 @@
1
+ require 'cocoapods-core/source/validator'
2
+
3
+ module Pod
4
+
5
+ # The Source class is responsible to manage a collection of podspecs.
6
+ #
7
+ # The backing store of the podspecs collection is an implementation detail
8
+ # abstracted from the rest of CocoaPods.
9
+ #
10
+ # The default implementation uses a git repo as a backing store, where the
11
+ # podspecs are namespaced as:
12
+ #
13
+ # "#{SPEC_NAME}/#{VERSION}/#{SPEC_NAME}.podspec"
14
+ #
15
+ class Source
16
+
17
+ # @return [Pathname] the location of the repo of the source.
18
+ #
19
+ attr_reader :repo
20
+
21
+ # @param [Pathname] repo @see #repo.
22
+ #
23
+ def initialize(repo)
24
+ @repo = repo
25
+ end
26
+
27
+ # @return [String] the name of the source.
28
+ #
29
+ def name
30
+ @repo.basename.to_s
31
+ end
32
+
33
+ alias_method :to_s, :name
34
+
35
+
36
+ # @return [Integer] compares a source with another one for sorting
37
+ # purposes.
38
+ #
39
+ # @note Source are compared by the alphabetical order of their name, and
40
+ # this convention should be used in any case where sources need to
41
+ # be disambiguated.
42
+ #
43
+ def <=> (other)
44
+ name <=> other.name
45
+ end
46
+
47
+ #---------------------------------------------------------------------------#
48
+
49
+ # @!group Queering the source
50
+
51
+ # @return [Array<String>] the list of the name of all the Pods.
52
+ #
53
+ def pods
54
+ @repo.children.map do |child|
55
+ child.basename.to_s if child.directory? && child.basename.to_s != '.git'
56
+ end.compact
57
+ end
58
+
59
+ # @return [Array<Sets>] the sets of all the Pods.
60
+ #
61
+ def pod_sets
62
+ pods.map { |pod| Specification::Set.new(pod, self) }
63
+ end
64
+
65
+ # @return [Array<Version>] all the available versions for the Pod, sorted
66
+ # from highest to lowest.
67
+ #
68
+ # @param [String] name
69
+ # the name of the Pod.
70
+ #
71
+ def versions(name)
72
+ pod_dir = repo + name
73
+ return unless pod_dir.exist?
74
+ pod_dir.children.map do |v|
75
+ basename = v.basename.to_s
76
+ Version.new(basename) if v.directory? && basename[0,1] != '.'
77
+ end.compact.sort.reverse
78
+ end
79
+
80
+ # @return [Specification] the specification for a given version of Pod.
81
+ #
82
+ # @param [String] name
83
+ # the name of the Pod.
84
+ #
85
+ # @param [Version,String] version
86
+ # the version for the specification.
87
+ #
88
+ def specification(name, version)
89
+ path = repo + name + version.to_s
90
+ specification_path = path + "#{name}.podspec.yaml"
91
+ unless specification_path.exist?
92
+ specification_path = path + "#{name}.podspec"
93
+ end
94
+ Specification.from_file(specification_path)
95
+ end
96
+
97
+ # @return [Array<Specification>] all the specifications contained by the
98
+ # source.
99
+ #
100
+ def all_specs
101
+ specs = pods.map do |name|
102
+ begin
103
+ versions(name).map { |version| specification(name, version) }
104
+ rescue DSLError => e
105
+ CoreUI.warn "Skipping `#{name}` because the podspec contains errors."
106
+ next
107
+ end
108
+ end
109
+ specs.flatten.compact
110
+ end
111
+
112
+ #---------------------------------------------------------------------------#
113
+
114
+ # @!group Searching the source
115
+
116
+ # @return [Set] a set for a given dependency. The set is identified by the
117
+ # name of the dependency and takes into account subspecs.
118
+ #
119
+ def search(dependency)
120
+ pod_sets.find do |set|
121
+ # First match the (top level) name, which does not yet load the spec from disk
122
+ set.name == dependency.root_name &&
123
+ # Now either check if it's a dependency on the top level spec, or if it's not
124
+ # check if the requested subspec exists in the top level spec.
125
+ set.specification.subspec_by_name(dependency.name)
126
+ end
127
+ end
128
+
129
+ # @return [Array<Set>] The list of the sets that contain the search term.
130
+ #
131
+ # @param [String] query
132
+ # the search term.
133
+ #
134
+ # @param [Bool] full_text_search
135
+ # whether the search should be limited to the name of the Pod or
136
+ # should include also the author, the summary, and the description.
137
+ #
138
+ # @note full text search requires to load the specification for each pod,
139
+ # hence is considerably slower.
140
+ #
141
+ def search_by_name(query, full_text_search = false)
142
+ pod_sets.map do |set|
143
+ if full_text_search
144
+ begin
145
+ s = set.specification
146
+ text = "#{s.name} #{s.authors} #{s.summary} #{s.description}"
147
+ rescue
148
+ CoreUI.warn "Skipping `#{set.name}` because the podspec contains errors."
149
+ end
150
+ else
151
+ text = set.name
152
+ end
153
+ set if text && text.downcase.include?(query.downcase)
154
+ end.compact
155
+ end
156
+
157
+ #---------------------------------------------------------------------------#
158
+
159
+ # @!group Representations
160
+
161
+ # @return [Hash{String=>{String=>Specification}}] the static representation
162
+ # of all the specifications grouped first by name and then by
163
+ # version.
164
+ #
165
+ def to_hash
166
+ hash = {}
167
+ all_specs.each do |spec|
168
+ print '.'
169
+ hash[spec.name] ||= {}
170
+ hash[spec.name][spec.version.version] = spec.to_hash
171
+ end
172
+ hash
173
+ end
174
+
175
+ # @return [String] the YAML encoded {to_hash} representation.
176
+ #
177
+ def to_yaml
178
+ require 'yaml'
179
+ to_hash.to_yaml
180
+ end
181
+
182
+ # @return [String] the JSON encoded {to_hash} representation.
183
+ #
184
+ def to_json
185
+ require 'json'
186
+ to_hash.to_json
187
+ end
188
+
189
+ #-------------------------------------------------------------------------#
190
+
191
+ # The Aggregate manages a directory of sources repositories.
192
+ #
193
+ class Aggregate
194
+
195
+ # @return [Pathname] the directory were the repositories are stored.
196
+ #
197
+ attr_reader :repos_dir
198
+
199
+ # @param [Pathname] repos_dir @see repos_dir.
200
+ #
201
+ def initialize(repos_dir)
202
+ @repos_dir = repos_dir
203
+ end
204
+
205
+ # @return [Array<Source>] all the sources.
206
+ #
207
+ def all
208
+ @sources ||= dirs.map { |repo| Source.new(repo) }.sort_by(&:name)
209
+ end
210
+
211
+ # @return [Array<String>] the names of all the pods available.
212
+ #
213
+ def all_pods
214
+ all.map(&:pods).flatten.uniq
215
+ end
216
+
217
+ # @return [Array<Set>] the sets for all the pods available.
218
+ #
219
+ # @note Implementation detail: The sources don't cache their values
220
+ # because they might change in response to an update. Therefore
221
+ # this method to prevent slowness caches the values before
222
+ # processing them.
223
+ #
224
+ def all_sets
225
+ pods_by_source = {}
226
+ all.each do |source|
227
+ pods_by_source[source] = source.pods
228
+ end
229
+ sources = pods_by_source.keys
230
+ pods = pods_by_source.values.flatten.uniq
231
+
232
+ pods.map do |pod|
233
+ pod_sources = sources.select{ |s| pods_by_source[s].include?(pod) }.compact
234
+ Specification::Set.new(pod, pod_sources)
235
+ end
236
+ end
237
+
238
+ # @return [Set, nil] a set for a given dependency including all the
239
+ # {Source} that contain the Pod. If no sources containing the
240
+ # Pod where found it returns nil.
241
+ #
242
+ # @raise If no source including the set can be found.
243
+ #
244
+ # @see Source#search
245
+ #
246
+ def search(dependency)
247
+ sources = all.select { |s| !s.search(dependency).nil? }
248
+ Specification::Set.new(dependency.root_name, sources) unless sources.empty?
249
+ end
250
+
251
+ # @return [Array<Set>] the sets that contain the search term.
252
+ #
253
+ # @raise If no source including the set can be found.
254
+ #
255
+ # @see Source#search_by_name
256
+ #
257
+ def search_by_name(query, full_text_search = false)
258
+ pods_by_source = {}
259
+ result = []
260
+ all.each { |s| pods_by_source[s] = s.search_by_name(query, full_text_search).map(&:name) }
261
+ root_spec_names = pods_by_source.values.flatten.uniq
262
+ root_spec_names.each do |pod|
263
+ sources = []
264
+ pods_by_source.each{ |source, pods| sources << source if pods.include?(pod) }
265
+ result << Specification::Set.new(pod, sources)
266
+ end
267
+ if result.empty?
268
+ extra = ", author, summary, or description" if full_text_search
269
+ raise(Informative, "Unable to find a pod with name" \
270
+ "#{extra} matching `#{query}'")
271
+ end
272
+ result
273
+ end
274
+
275
+ # @return [Array<Pathname>] the directories where the sources are stored.
276
+ #
277
+ # @raise If the repos dir doesn't exits.
278
+ #
279
+ def dirs
280
+ repos_dir.children.select(&:directory?)
281
+ end
282
+ end
283
+ end
284
+ end
@@ -0,0 +1,356 @@
1
+ require 'active_support/core_ext/string/strip.rb'
2
+
3
+ module Pod
4
+ class Specification
5
+
6
+ # Allows to conveniently access a Specification programmatically.
7
+ #
8
+ # It takes care of:
9
+ #
10
+ # - standardizing the attributes
11
+ # - handling multi-platform values
12
+ # - handle default values
13
+ # - handle inherited values
14
+ #
15
+ # This class allows to store the values of the attributes in the
16
+ # Specification as specified in the DSL. The benefits is reduced reliance
17
+ # on meta programming to access the attributes and the possibility of
18
+ # serializing a specification back exactly as defined in a file.
19
+ #
20
+ class Consumer
21
+
22
+ # @return [Specification] The specification to consume.
23
+ #
24
+ attr_reader :spec
25
+
26
+ # @return [Symbol] The name of the platform for which the specification
27
+ # needs to be consumed.
28
+ #
29
+ attr_reader :platform_name
30
+
31
+ # @param [Specification] spec @see spec
32
+ # @param [Symbol, Platform] platform
33
+ # The platform for which the specification needs to be consumed.
34
+ #
35
+ def initialize(spec, platform)
36
+ @spec = spec
37
+ @platform_name = platform.is_a?(Symbol) ? platform : platform.name
38
+
39
+ unless spec.supported_on_platform?(platform)
40
+ raise StandardError, "#{to_s} is not compatible with #{platform}."
41
+ end
42
+ end
43
+
44
+ # Creates a method to access the contents of the attribute.
45
+ #
46
+ # @param [Symbol] name
47
+ # the name of the attribute.
48
+ #
49
+ # @macro [attach]
50
+ # @!method $1
51
+ #
52
+ def self.spec_attr_accessor(name)
53
+ define_method(name) do
54
+ value_for_attribute(name)
55
+ end
56
+ end
57
+
58
+ #-----------------------------------------------------------------------#
59
+
60
+ # @!group Regular attributes
61
+
62
+ # @return [Bool] Whether the source files of the specification require to
63
+ # be compiled with ARC.
64
+ #
65
+ spec_attr_accessor :requires_arc
66
+ alias_method :requires_arc?, :requires_arc
67
+
68
+ # @return [Array<String>] A list of frameworks that the user’s target
69
+ # needs to link against
70
+ #
71
+ spec_attr_accessor :frameworks
72
+
73
+ # @return [Array<String>] A list of frameworks that the user’s target
74
+ # needs to **weakly** link against
75
+ #
76
+ spec_attr_accessor :weak_frameworks
77
+
78
+ # @return [Array<String>] A list of libraries that the user’s target
79
+ # needs to link against
80
+ #
81
+ spec_attr_accessor :libraries
82
+
83
+ # @return [Array<String>] the list of compiler flags needed by the
84
+ # specification files.
85
+ #
86
+ spec_attr_accessor :compiler_flags
87
+
88
+ # @return [Hash{String => String}] the xcconfig flags for the current
89
+ # specification.
90
+ #
91
+ spec_attr_accessor :xcconfig
92
+
93
+ # @return [String] The contents of the prefix header.
94
+ #
95
+ spec_attr_accessor :prefix_header_contents
96
+
97
+ # @return [String] The path of the prefix header file.
98
+ #
99
+ spec_attr_accessor :prefix_header_file
100
+
101
+ # @return [String] the headers directory.
102
+ #
103
+ spec_attr_accessor :header_dir
104
+
105
+ # @return [String] the directory from where to preserve the headers
106
+ # namespacing.
107
+ #
108
+ spec_attr_accessor :header_mappings_dir
109
+
110
+ #-----------------------------------------------------------------------#
111
+
112
+ # @!group File patterns
113
+
114
+ # @return [Array<String>] the source files of the Pod.
115
+ #
116
+ spec_attr_accessor :source_files
117
+
118
+ # @return [Array<String>] the public headers of the Pod.
119
+ #
120
+ spec_attr_accessor :public_header_files
121
+
122
+ # @return [Array<String>] A hash where the key represents the
123
+ # paths of the resources to copy and the values the paths of
124
+ # the resources that should be copied.
125
+ #
126
+ spec_attr_accessor :resources
127
+
128
+ # @return [Array<String>] The file patterns that the
129
+ # Pod should ignore.
130
+ #
131
+ spec_attr_accessor :exclude_files
132
+
133
+ # @return [Array<String>] The paths that should be not
134
+ # cleaned.
135
+ #
136
+ spec_attr_accessor :preserve_paths
137
+
138
+ #-----------------------------------------------------------------------#
139
+
140
+ # @!group Dependencies
141
+
142
+ # @return [Array<Dependency>] the dependencies on other Pods.
143
+ #
144
+ def dependencies
145
+ value = value_for_attribute(:dependencies)
146
+ value.map do |name, requirements|
147
+ Dependency.new(name, requirements)
148
+ end
149
+ end
150
+
151
+ #-----------------------------------------------------------------------#
152
+
153
+ private
154
+
155
+ # Returns the value for the attribute with the given name for the
156
+ # specification. It takes into account inheritance, multi-platform
157
+ # attributes and default values.
158
+ #
159
+ # @param [Symbol] attr_name
160
+ # The name of the attribute.
161
+ #
162
+ # @return [String, Array, Hash] the value for the attribute.
163
+ #
164
+ def value_for_attribute(attr_name)
165
+ attr = Specification::DSL.attributes[attr_name]
166
+ value = value_with_inheritance(spec, attr)
167
+ value ||= attr.default(platform_name)
168
+ value ||= attr.container.new if attr.container
169
+ value
170
+ end
171
+
172
+ # Returns the value of a given attribute taking into account inheritance.
173
+ #
174
+ # @param [Specification] the_spec
175
+ # the specification for which the value is needed.
176
+ #
177
+ # @param [Specification::DSL::Attribute] attr
178
+ # the attribute for which that value is needed.
179
+ #
180
+ # @return [String, Array, Hash] the value for the attribute.
181
+ #
182
+ def value_with_inheritance(the_spec, attr)
183
+ value = raw_value_for_attribute(the_spec, attr)
184
+ if the_spec.root? || !attr.inherited?
185
+ return value
186
+ end
187
+
188
+ parent_value = value_with_inheritance(the_spec.parent, attr)
189
+ merge_values(attr, parent_value, value)
190
+ end
191
+
192
+ # Returns the value of a given attribute taking into account multi
193
+ # platform values.
194
+ #
195
+ # @param [Specification] the_spec
196
+ # the specification for which the value is needed.
197
+ #
198
+ # @param [Specification::DSL::Attribute] attr
199
+ # the attribute for which that value is needed.
200
+ #
201
+ # @return [String, Array, Hash] The value for an attribute.
202
+ #
203
+ def raw_value_for_attribute(the_spec, attr)
204
+ value = the_spec.attributes_hash[attr.name.to_s]
205
+ value = prepare_value(attr, value)
206
+
207
+ if attr.multi_platform? && the_spec.attributes_hash[platform_name.to_s]
208
+ platform_value = the_spec.attributes_hash[platform_name.to_s][attr.name.to_s]
209
+ platform_value = prepare_value(attr, platform_value)
210
+ value = merge_values(attr, value, platform_value)
211
+ end
212
+ value
213
+ end
214
+
215
+ # Merges the values of an attribute, either because the attribute is
216
+ # multi platform or because it is inherited.
217
+ #
218
+ # @param [Specification::DSL::Attribute] attr
219
+ # the attribute for which that value is needed.
220
+ #
221
+ # @param [String, Array, Hash] existing_value
222
+ # the current value (the value of the parent or non-multiplatform
223
+ # value).
224
+ #
225
+ # @param [String, Array, Hash] new_value
226
+ # the value to append (the value of the spec or the
227
+ # multi-platform value).
228
+ #
229
+ # @return [String, Array, Hash] The merged value.
230
+ #
231
+ def merge_values(attr, existing_value, new_value)
232
+ return existing_value if new_value.nil?
233
+ return new_value if existing_value.nil?
234
+
235
+ if attr.types.include?(TrueClass)
236
+ new_value.nil? ? existing_value : new_value
237
+ elsif attr.container == Array
238
+ r = [*existing_value] + [*new_value]
239
+ r.compact
240
+ elsif attr.container == Hash
241
+ existing_value = existing_value.merge(new_value) do |_, old, new|
242
+ if new.is_a?(Array) || old.is_a?(Array)
243
+ r = [*old] + [*new]
244
+ r.compact
245
+ else
246
+ old + ' ' + new
247
+ end
248
+ end
249
+ else
250
+ value
251
+ end
252
+ end
253
+
254
+ # Wraps a value in an Array if needed and calls the prepare hook to
255
+ # allow further customization of a value before storing it in the
256
+ # instance variable.
257
+ #
258
+ # @note Only array containers are wrapped. To automatically wrap
259
+ # values for attributes with hash containers a prepare hook
260
+ # should be used.
261
+ #
262
+ # @return [Object] the customized value of the original one if no
263
+ # prepare hook was defined.
264
+ #
265
+ def prepare_value(attr, value)
266
+ if attr.container == Array
267
+ if value.class == Rake::FileList
268
+ value = [value]
269
+ else
270
+ value = [*value].compact
271
+ end
272
+ end
273
+
274
+ hook_name = prepare_hook_name(attr)
275
+ if self.respond_to?(hook_name, true)
276
+ value = self.send(hook_name, value)
277
+ else
278
+ value
279
+ end
280
+ end
281
+
282
+ #-----------------------------------------------------------------------#
283
+
284
+ private
285
+
286
+ # Converts the keys of the given hash to a string.
287
+ #
288
+ # @todo Removed if not used by `resources_bundle`
289
+ #
290
+ # @param [Object] value
291
+ # the value that needs to be stripped from the Symbols.
292
+ #
293
+ # @return [Hash] the hash with the strings instead of the keys.
294
+ #
295
+ # def convert_keys_to_symbol(value)
296
+ # return unless value
297
+ # result = {}
298
+ # value.each do |key, subvalue|
299
+ # subvalue = convert_keys_to_symbol(subvalue) if subvalue.is_a?(Hash)
300
+ # result[key.to_sym] = subvalue
301
+ # end
302
+ # result
303
+ # end
304
+
305
+ #-----------------------------------------------------------------------#
306
+
307
+ private
308
+
309
+ # @!group Preparing Values
310
+ #
311
+ # Raw values need to be prepared as soon as they are read so they can be
312
+ # safely merged to support multi platform attributes and inheritance
313
+
314
+ # @return [String] the name of the prepare hook for this attribute.
315
+ #
316
+ # @note The hook is called after the value has been wrapped in an
317
+ # array (if needed according to the container) but before
318
+ # validation.
319
+ #
320
+ def prepare_hook_name(attr)
321
+ "_prepare_#{attr.name}"
322
+ end
323
+
324
+ # Converts the prefix header to a string if specified as an array.
325
+ #
326
+ # @param [String, Array] value.
327
+ # The value of the attribute as specified by the user.
328
+ #
329
+ # @return [String] the prefix header.
330
+ #
331
+ def _prepare_prefix_header_contents(value)
332
+ value.is_a?(Array) ? value * "\n" : value
333
+ end
334
+
335
+ # Converts the resources file patterns to a hash defaulting to the
336
+ # resource key if they are defined as an Array or a String.
337
+ #
338
+ # @param [String, Array, Hash] value.
339
+ # The value of the attribute as specified by the user.
340
+ #
341
+ # @return [Hash] the resources.
342
+ #
343
+ # def _prepare_resources_bundle(value)
344
+ # value = { :resources => value } unless value.is_a?(Hash)
345
+ # result = {}
346
+ # value.each do |key, patterns|
347
+ # result[key] = [*patterns].compact
348
+ # end
349
+ # result
350
+ # end
351
+
352
+ #-----------------------------------------------------------------------#
353
+
354
+ end
355
+ end
356
+ end