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,345 @@
1
+ require 'cocoapods-core/podfile/dsl'
2
+ require 'cocoapods-core/podfile/target_definition'
3
+
4
+ module Pod
5
+
6
+ # The Podfile is a specification that describes the dependencies of the
7
+ # targets of an Xcode project.
8
+ #
9
+ # It supports its own DSL and generally is stored in files named
10
+ # `CocoaPods.podfile` or `Podfile`.
11
+ #
12
+ # The Podfile creates a hierarchy of target definitions that that store the
13
+ # information of necessary to generate the CocoaPods libraries.
14
+ #
15
+ class Podfile
16
+
17
+ # @!group DSL support
18
+
19
+ include Pod::Podfile::DSL
20
+
21
+ #-------------------------------------------------------------------------#
22
+
23
+ class Pod::Podfile::StandardError < StandardError; end
24
+
25
+ #-------------------------------------------------------------------------#
26
+
27
+ # @return [Pathname] the path where the podfile was loaded from. It is nil
28
+ # if the podfile was generated programmatically.
29
+ #
30
+ attr_accessor :defined_in_file
31
+
32
+ # @param [Pathname] defined_in_file
33
+ # the path of the podfile.
34
+ #
35
+ # @param [Proc] block
36
+ # an optional block that configures the podfile through the DSL.
37
+ #
38
+ # @example Creating a Podfile.
39
+ #
40
+ # platform :ios, "6.0"
41
+ # target :my_app do
42
+ # pod "AFNetworking", "~> 1.0"
43
+ # end
44
+ #
45
+ def initialize(defined_in_file = nil, internal_hash = {}, &block)
46
+ self.defined_in_file = defined_in_file
47
+ @internal_hash = internal_hash
48
+ if block
49
+ default_target_def = TargetDefinition.new(:default, self)
50
+ @root_target_definitions = [default_target_def]
51
+ @current_target_definition = default_target_def
52
+ instance_eval(&block)
53
+ else
54
+ @root_target_definitions = []
55
+ end
56
+ end
57
+
58
+ # @return [String] a string useful to represent the Podfile in a message
59
+ # presented to the user.
60
+ #
61
+ def to_s
62
+ "Podfile"
63
+ end
64
+
65
+ #-------------------------------------------------------------------------#
66
+
67
+ public
68
+
69
+ # @!group Working with a podfile
70
+
71
+ # @return [Hash{Symbol,String => TargetDefinition}] the target definitions
72
+ # of the podfile stored by their name.
73
+ #
74
+ def target_definitions
75
+ Hash[target_definition_list.map { |td| [td.name, td] }]
76
+ end
77
+
78
+ def target_definition_list
79
+ root_target_definitions.map { |td| [td, td.recursive_children] }.flatten
80
+ end
81
+
82
+ # @return [Array<TargetDefinition>] The root target definition.
83
+ #
84
+ attr_accessor :root_target_definitions
85
+
86
+ # @return [Array<Dependency>] the dependencies of the all the target
87
+ # definitions.
88
+ #
89
+ def dependencies
90
+ target_definition_list.map(&:dependencies).flatten.uniq
91
+ end
92
+
93
+ #-------------------------------------------------------------------------#
94
+
95
+ public
96
+
97
+ # @!group Attributes
98
+
99
+ # @return [String] the path of the workspace if specified by the user.
100
+ #
101
+ def workspace_path
102
+ path = get_hash_value('workspace')
103
+ if path
104
+ if File.extname(path) == '.xcworkspace'
105
+ path
106
+ else
107
+ "#{path}.xcworkspace"
108
+ end
109
+ end
110
+ end
111
+
112
+ # @return [Bool] whether the podfile should generate a BridgeSupport
113
+ # metadata document.
114
+ #
115
+ def generate_bridge_support?
116
+ get_hash_value('generate_bridge_support')
117
+ end
118
+
119
+ # @return [Bool] whether the -fobjc-arc flag should be added to the
120
+ # OTHER_LD_FLAGS.
121
+ #
122
+ def set_arc_compatibility_flag?
123
+ get_hash_value('set_arc_compatibility_flag')
124
+ end
125
+
126
+ #-------------------------------------------------------------------------#
127
+
128
+ public
129
+
130
+ # @!group Hooks
131
+
132
+ # Calls the pre install callback if defined.
133
+ #
134
+ # @param [Pod::Installer] installer
135
+ # the installer that is performing the installation.
136
+ #
137
+ # @return [Bool] whether a pre install callback was specified and it was
138
+ # called.
139
+ #
140
+ def pre_install!(installer)
141
+ if @pre_install_callback
142
+ @pre_install_callback.call(installer)
143
+ true
144
+ else
145
+ false
146
+ end
147
+ end
148
+
149
+ # Calls the post install callback if defined.
150
+ #
151
+ # @param [Pod::Installer] installer
152
+ # the installer that is performing the installation.
153
+ #
154
+ # @return [Bool] whether a post install callback was specified and it was
155
+ # called.
156
+ #
157
+ def post_install!(installer)
158
+ if @post_install_callback
159
+ @post_install_callback.call(installer)
160
+ true
161
+ else
162
+ false
163
+ end
164
+ end
165
+
166
+ #-------------------------------------------------------------------------#
167
+
168
+ public
169
+
170
+ # @!group Representations
171
+
172
+ # @return [Array] The keys used by the hash representation of the Podfile.
173
+ #
174
+ HASH_KEYS = [
175
+ 'target_definitions',
176
+ 'workspace',
177
+ 'generate_bridge_support',
178
+ 'set_arc_compatibility_flag',
179
+ ].freeze
180
+
181
+ # @return [Hash] The hash representation of the Podfile.
182
+ #
183
+ def to_hash
184
+ hash = {}
185
+ hash['target_definitions'] = Hash[root_target_definitions.map { |child| [child.name, child.to_hash] }]
186
+ hash.merge!(internal_hash)
187
+ hash
188
+ end
189
+
190
+ # @return [String] The YAML representation of the Podfile.
191
+ #
192
+ def to_yaml
193
+ to_hash.to_yaml
194
+ end
195
+
196
+ #-------------------------------------------------------------------------#
197
+
198
+ public
199
+
200
+ # @!group Class methods
201
+
202
+ # Initializes a podfile from the file with the given path.
203
+ #
204
+ # @param [Pathname] path
205
+ # the path from where the podfile should be loaded.
206
+ #
207
+ # @return [Podfile] the generated podfile.
208
+ #
209
+ def self.from_file(path)
210
+ path = Pathname.new(path)
211
+ unless path.exist?
212
+ raise StandardError, "No Podfile exists at path `#{path}`."
213
+ end
214
+ string = File.open(path, 'r:utf-8') { |f| f.read }
215
+ # Work around for Rubinius incomplete encoding in 1.9 mode
216
+ if string.respond_to?(:encoding) && string.encoding.name != "UTF-8"
217
+ string.encode!('UTF-8')
218
+ end
219
+
220
+ case path.extname
221
+ when ''
222
+ Podfile.from_ruby(string, path)
223
+ when '.yaml', '.cocoapods'
224
+ Podfile.from_yaml(string, path)
225
+ else
226
+ raise StandardError, "Unsupported Podfile format `#{path}`."
227
+ end
228
+ end
229
+
230
+ # Configures a new Podfile from the given ruby string.
231
+ #
232
+ # @param [String] string
233
+ # The ruby string which will configure the podfile with the DSL.
234
+ #
235
+ # @param [Pathname] path
236
+ # The path from which the Podfile is loaded.
237
+ #
238
+ # @return [Podfile] the new Podfile
239
+ #
240
+ def self.from_ruby(string, path = nil)
241
+ podfile = Podfile.new(path) do
242
+ begin
243
+ eval(string, nil, path.to_s)
244
+ rescue Exception => e
245
+ raise DSLError.new("Invalid `#{path.basename}` file: #{e.message}", path, e.backtrace)
246
+ end
247
+ end
248
+ podfile
249
+ end
250
+
251
+ # Configures a new Podfile from the given hash.
252
+ #
253
+ # @param [Hash] hash
254
+ # The hash which contains the information of the Podfile.
255
+ #
256
+ # @param [Pathname] path
257
+ # The path from which the Podfile is loaded.
258
+ #
259
+ # @return [Podfile] the new Podfile
260
+ #
261
+ def self.from_hash(hash, path = nil)
262
+ internal_hash = hash.dup
263
+ target_definitions = internal_hash.delete('target_definitions') || []
264
+ podfile = Podfile.new(path,internal_hash)
265
+ target_definitions.each do |name, definition_hash|
266
+ definition = TargetDefinition.from_hash(name, definition_hash, podfile)
267
+ podfile.root_target_definitions << definition
268
+ end
269
+ podfile
270
+ end
271
+
272
+ # Configures a new Podfile from the given YAML representation.
273
+ #
274
+ # @param [String] yaml
275
+ # The YAML encoded hash which contains the information of the
276
+ # Podfile.
277
+ #
278
+ # @param [Pathname] path
279
+ # The path from which the Podfile is loaded.
280
+ #
281
+ # @return [Podfile] the new Podfile
282
+ #
283
+ def self.from_yaml(yaml, path = nil)
284
+ hash = YAML.load(yaml)
285
+ from_hash(hash)
286
+ end
287
+
288
+ #-------------------------------------------------------------------------#
289
+
290
+ private
291
+
292
+ # @!group Private helpers
293
+
294
+ # @return [Hash] The hash which store the attributes of the Podfile.
295
+ #
296
+ attr_accessor :internal_hash
297
+
298
+ # Set a value in the internal hash of the Podfile for the given key.
299
+ #
300
+ # @param [String] key
301
+ # The key for which to store the value.
302
+ #
303
+ # @param [Object] value
304
+ # The value to store.
305
+ #
306
+ # @raise If the key is not recognized.
307
+ #
308
+ # @return [void]
309
+ #
310
+ def set_hash_value(key, value)
311
+ raise StandardError, "Unsupported hash key `#{key}`" unless HASH_KEYS.include?(key)
312
+ internal_hash[key] = value
313
+ end
314
+
315
+ # Returns the value for the given key in the internal hash of the Podfile.
316
+ #
317
+ # @param [String] key
318
+ # The key for which the value is needed.
319
+ #
320
+ # @raise If the key is not recognized.
321
+ #
322
+ # @return [Object] The value for the key.
323
+ #
324
+ def get_hash_value(key)
325
+ raise StandardError, "Unsupported hash key `#{key}`" unless HASH_KEYS.include?(key)
326
+ internal_hash[key]
327
+ end
328
+
329
+ # @return [TargetDefinition] The current target definition to which the DSL
330
+ # commands apply.
331
+ #
332
+ attr_accessor :current_target_definition
333
+
334
+ #-------------------------------------------------------------------------#
335
+
336
+ # @deprecated Deprecated in favour of the more succinct {#pod}. Remove for
337
+ # CocoaPods 1.0.
338
+ #
339
+ def dependency(name = nil, *requirements, &block)
340
+ warn "[DEPRECATED] `dependency' is deprecated (use `pod')"
341
+ pod(name, *requirements, &block)
342
+ end
343
+
344
+ end
345
+ end
@@ -0,0 +1,15 @@
1
+ module Pod
2
+
3
+ # A Requirement is a set of one or more version restrictions of a
4
+ # {Dependency}.
5
+ #
6
+ # It is based on the RubyGems class adapted to support CocoaPods specific
7
+ # information.
8
+ #
9
+ # @todo Move support about external sources and head information here from
10
+ # the Dependency class.
11
+ #
12
+ class Requirement < Pod::Vendor::Gem::Requirement
13
+ end
14
+
15
+ end
@@ -0,0 +1,183 @@
1
+ module Pod
2
+ class Source
3
+
4
+ # TODO: THIS CLASS IS A STUB
5
+
6
+ # Checks whether a podspec can be accepted by a source.
7
+ #
8
+ # This class can work on Travis but some checks are lost as the repo is
9
+ # already merged during the test.
10
+ #
11
+ class Validator
12
+
13
+ # @return [Source] the source where the podspec should be added.
14
+ #
15
+ attr_reader :source
16
+
17
+ # @param [Pathname] repo @see Source#repo.
18
+ #
19
+ def initialize(repo)
20
+ @source = Source.new(repo)
21
+ @errors = {}
22
+ @linter_results = {}
23
+ end
24
+
25
+ # @param [Array<Pathname>] spec_paths
26
+ # a list of path that should be checked for being accepted in
27
+ # specs repo.
28
+ #
29
+ # @return [Bool] whether to podspec can be accepted by the source.
30
+ #
31
+ def check(spec_paths)
32
+ spec_paths = [ spec_paths ] unless spec_paths.is_a?(Array)
33
+ @errors = {}
34
+ spec_paths.each do |path|
35
+ @spec_path = Pathname.new(path)
36
+ lint
37
+ next unless spec
38
+ # check_spec_path
39
+ check_spec_source_change
40
+ check_if_untagged_version_is_acceptable
41
+ check_commit_change_for_untagged_version
42
+ check_dependencies
43
+ end
44
+ errors.values.empty?
45
+ end
46
+
47
+ #-----------------------------------------------------------------------#
48
+
49
+ # @!group Validation results
50
+
51
+ public
52
+
53
+
54
+ # @return [Hash{Pathname=>Array<String>}] the errors generated by the
55
+ # validation. If there is any error the podspec cannot be
56
+ # accepted.
57
+ #
58
+ attr_reader :errors
59
+
60
+ # @return [Hash{Pathname=>Array<Specification::Linter::Result>}] the
61
+ # result generated by the linter for not approved specifications.
62
+ #
63
+ attr_reader :linter_results
64
+
65
+ #-----------------------------------------------------------------------#
66
+
67
+ # @!group Validation helpers
68
+
69
+ private
70
+
71
+ # @return [Pathname] The path of the current specification that should be
72
+ # checked.
73
+ #
74
+ attr_reader :spec_path
75
+
76
+ # @return [Specification] The current specification that should be
77
+ # checked.
78
+ #
79
+ # @note The specification is generated by the linter that catches any
80
+ # exception.
81
+ #
82
+ attr_reader :spec
83
+
84
+
85
+ #
86
+ #
87
+ def error(message)
88
+ @errors[spec_path] ||= []
89
+ @errors[spec_path] << message
90
+ end
91
+
92
+ #-----------------------------------------------------------------------#
93
+
94
+ # @!group Check steps
95
+
96
+ private
97
+
98
+ def lint
99
+ linter = Specification::Linter.new(spec_path)
100
+ if linter.lint
101
+ @spec = linter.spec
102
+ else
103
+ error 'Linter failed validation.'
104
+ end
105
+ end
106
+
107
+ # TODO: this check cannot be performed before a merge.
108
+ def check_spec_path
109
+ expected = "#{spec.name}/#{spec.version}/#{spec.name}.podspec"
110
+ relative_path = spec_path.relative_path_from(source.repo).to_s
111
+ unless relative_path == expected
112
+ error "Incorrect path, the path is `#{relative_path}` and should be `#{expected}`."
113
+ end
114
+ end
115
+
116
+ def check_spec_source_change
117
+ return unless spec
118
+ return unless reference_spec
119
+ keys = Spec::DSL::SOURCE_KEYS.keys
120
+ source = spec.source.values_at(*keys).compact.first
121
+ old_source = reference_spec.source.values_at(*keys).compact.first
122
+ unless source == old_source
123
+ error "Attempt to change the source of the specification. " \
124
+ "Source: `#{source}`. Previous: `#{old_source}`.\n " \
125
+ "Contact specs repos maintainers if the library changed location."
126
+ end
127
+ end
128
+
129
+ def check_if_untagged_version_is_acceptable
130
+ return unless spec
131
+ return if !spec.source[:git] || spec.source[:tag]
132
+
133
+ # Allow to fix a 0.0.1 podspec
134
+ if !related_specifications.any? { |s| s.version == '0.0.1' }
135
+ error "There is already versioned specifications so " \
136
+ "untagged versions cannot be added."
137
+ elsif spec.version != Version.new('0.0.1')
138
+ error "Untagged Git repositories should be versioned as 0.0.1"
139
+ end
140
+ end
141
+
142
+ # TODO: this cannot be tested on Travis with the current setup
143
+ def check_commit_change_for_untagged_version
144
+ return unless spec
145
+ return unless spec.version == Version.new('0.0.1')
146
+ ref_spec = related_specifications.find { |s| s.version != '0.0.1' }
147
+ return unless ref_spec
148
+ unless ref_spec.source[:commit] == spec.source[:commit]
149
+ error "Attempt to rewrite the commit of 0.0.1 version."
150
+ end
151
+ end
152
+
153
+ def check_dependencies
154
+ return unless spec
155
+ spec.external_dependencies(true).each do |dep|
156
+ set = source.search(dep)
157
+ unless set && set.specification
158
+ error "Unable to find a specification for the `#{dep}` dependency."
159
+ end
160
+ end
161
+ end
162
+
163
+ #-----------------------------------------------------------------------#
164
+
165
+ # @!group Source helpers
166
+
167
+ private
168
+
169
+ def related_specifications
170
+ versions = source.versions(spec.name)
171
+ return unless versions
172
+ specs = versions.sort.map { |v| source.specification(spec.name, v) }
173
+ specs.reject { |s| s.defined_in_file == spec_path }
174
+ end
175
+
176
+ def reference_spec
177
+ specs = related_specifications
178
+ specs.last if specs
179
+ end
180
+
181
+ end
182
+ end
183
+ end