cocoapods 0.5.1 → 0.6.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 (44) hide show
  1. data/CHANGELOG.md +229 -2
  2. data/README.md +50 -20
  3. data/bin/pod +3 -2
  4. data/lib/cocoapods.rb +23 -9
  5. data/lib/cocoapods/command.rb +71 -30
  6. data/lib/cocoapods/command/error_report.rb +102 -0
  7. data/lib/cocoapods/command/install.rb +27 -19
  8. data/lib/cocoapods/command/list.rb +51 -8
  9. data/lib/cocoapods/command/presenter.rb +61 -0
  10. data/lib/cocoapods/command/presenter/cocoa_pod.rb +123 -0
  11. data/lib/cocoapods/command/push.rb +102 -0
  12. data/lib/cocoapods/command/repo.rb +70 -14
  13. data/lib/cocoapods/command/search.rb +7 -10
  14. data/lib/cocoapods/command/setup.rb +76 -15
  15. data/lib/cocoapods/command/spec.rb +581 -97
  16. data/lib/cocoapods/config.rb +23 -26
  17. data/lib/cocoapods/dependency.rb +86 -40
  18. data/lib/cocoapods/downloader.rb +30 -18
  19. data/lib/cocoapods/downloader/git.rb +125 -15
  20. data/lib/cocoapods/downloader/http.rb +73 -0
  21. data/lib/cocoapods/downloader/mercurial.rb +3 -9
  22. data/lib/cocoapods/downloader/subversion.rb +3 -9
  23. data/lib/cocoapods/executable.rb +26 -3
  24. data/lib/cocoapods/generator/acknowledgements.rb +37 -0
  25. data/lib/cocoapods/generator/acknowledgements/markdown.rb +38 -0
  26. data/lib/cocoapods/generator/acknowledgements/plist.rb +63 -0
  27. data/lib/cocoapods/generator/copy_resources_script.rb +8 -4
  28. data/lib/cocoapods/generator/documentation.rb +99 -0
  29. data/lib/cocoapods/generator/dummy_source.rb +14 -0
  30. data/lib/cocoapods/installer.rb +140 -109
  31. data/lib/cocoapods/installer/target_installer.rb +78 -83
  32. data/lib/cocoapods/installer/user_project_integrator.rb +162 -0
  33. data/lib/cocoapods/local_pod.rb +240 -0
  34. data/lib/cocoapods/platform.rb +41 -18
  35. data/lib/cocoapods/podfile.rb +234 -21
  36. data/lib/cocoapods/project.rb +67 -0
  37. data/lib/cocoapods/resolver.rb +62 -32
  38. data/lib/cocoapods/sandbox.rb +63 -0
  39. data/lib/cocoapods/source.rb +42 -20
  40. data/lib/cocoapods/specification.rb +294 -271
  41. data/lib/cocoapods/specification/set.rb +10 -28
  42. data/lib/cocoapods/specification/statistics.rb +112 -0
  43. metadata +124 -11
  44. data/lib/cocoapods/xcodeproj_pods.rb +0 -111
@@ -1,26 +1,149 @@
1
1
  module Pod
2
2
  class Podfile
3
+ class UserProject
4
+ include Config::Mixin
5
+
6
+ DEFAULT_BUILD_CONFIGURATIONS = { 'Debug' => :debug, 'Release' => :release }.freeze
7
+
8
+ def initialize(path = nil, build_configurations = {})
9
+ self.path = path if path
10
+ @build_configurations = build_configurations.merge(DEFAULT_BUILD_CONFIGURATIONS)
11
+ end
12
+
13
+ def path=(path)
14
+ path = path.to_s
15
+ @path = Pathname.new(File.extname(path) == '.xcodeproj' ? path : "#{path}.xcodeproj")
16
+ @path = config.project_root + @path unless @path.absolute?
17
+ @path
18
+ end
19
+
20
+ def path
21
+ if @path
22
+ @path
23
+ else
24
+ xcodeprojs = config.project_root.glob('*.xcodeproj')
25
+ if xcodeprojs.size == 1
26
+ @path = xcodeprojs.first
27
+ end
28
+ end
29
+ end
30
+
31
+ def project
32
+ Xcodeproj::Project.new(path) if path && path.exist?
33
+ end
34
+
35
+ def build_configurations
36
+ if project
37
+ project.build_configurations.map(&:name).inject({}) do |hash, name|
38
+ hash[name] = :release; hash
39
+ end.merge(@build_configurations)
40
+ else
41
+ @build_configurations
42
+ end
43
+ end
44
+ end
45
+
3
46
  class TargetDefinition
4
- attr_reader :name, :parent, :target_dependencies
47
+ include Config::Mixin
5
48
 
6
- def initialize(name, parent = nil)
7
- @name, @parent, @target_dependencies = name, parent, []
49
+ attr_reader :name, :target_dependencies
50
+
51
+ attr_accessor :user_project, :link_with, :platform, :parent, :exclusive
52
+
53
+ def initialize(name, options = {})
54
+ @name, @target_dependencies = name, []
55
+ @parent, @exclusive = options.values_at(:parent, :exclusive)
8
56
  end
9
57
 
10
- def lib_name
58
+ # A target is automatically `exclusive` if the `platform` does not match
59
+ # the parent's `platform`.
60
+ def exclusive
61
+ if @exclusive.nil?
62
+ if @platform.nil?
63
+ false
64
+ else
65
+ @parent.platform != @platform
66
+ end
67
+ else
68
+ @exclusive
69
+ end
70
+ end
71
+ alias_method :exclusive?, :exclusive
72
+
73
+ def user_project
74
+ @user_project || @parent.user_project
75
+ end
76
+
77
+ def link_with=(targets)
78
+ @link_with = targets.is_a?(Array) ? targets : [targets]
79
+ end
80
+
81
+ def platform
82
+ @platform || (@parent.platform if @parent)
83
+ end
84
+
85
+ def label
11
86
  if name == :default
12
87
  "Pods"
13
- elsif @parent
14
- "#{@parent.lib_name}-#{name}"
15
- else
88
+ elsif exclusive?
16
89
  "Pods-#{name}"
90
+ else
91
+ "#{@parent.label}-#{name}"
92
+ end
93
+ end
94
+
95
+ def acknowledgements_path
96
+ config.project_pods_root + "#{label}-Acknowledgements"
97
+ end
98
+
99
+ # Returns a path, which is relative to the project_root, relative to the
100
+ # `$(SRCROOT)` of the user's project.
101
+ def relative_to_srcroot(path)
102
+ if user_project.path.nil?
103
+ # TODO this is not in the right place
104
+ raise Informative, "[!] Unable to find an Xcode project to integrate".red if config.integrate_targets
105
+ path
106
+ else
107
+ (config.project_root + path).relative_path_from(user_project.path.dirname)
17
108
  end
18
109
  end
19
110
 
111
+ def relative_pods_root
112
+ "${SRCROOT}/#{relative_to_srcroot "Pods"}"
113
+ end
114
+
115
+ def lib_name
116
+ "lib#{label}.a"
117
+ end
118
+
119
+ def xcconfig_name
120
+ "#{label}.xcconfig"
121
+ end
122
+
123
+ def xcconfig_relative_path
124
+ relative_to_srcroot("Pods/#{xcconfig_name}").to_s
125
+ end
126
+
127
+ def copy_resources_script_name
128
+ "#{label}-resources.sh"
129
+ end
130
+
131
+ def copy_resources_script_relative_path
132
+ "${SRCROOT}/#{relative_to_srcroot("Pods/#{copy_resources_script_name}")}"
133
+ end
134
+
135
+ def prefix_header_name
136
+ "#{label}-prefix.pch"
137
+ end
138
+
139
+ def bridge_support_name
140
+ "#{label}.bridgesupport"
141
+ end
142
+
20
143
  # Returns *all* dependencies of this target, not only the target specific
21
144
  # ones in `target_dependencies`.
22
145
  def dependencies
23
- @target_dependencies + (@parent ? @parent.dependencies : [])
146
+ @target_dependencies + (exclusive? ? [] : @parent.dependencies)
24
147
  end
25
148
 
26
149
  def empty?
@@ -40,7 +163,9 @@ module Pod
40
163
  include Config::Mixin
41
164
 
42
165
  def initialize(&block)
43
- @target_definitions = { :default => (@target_definition = TargetDefinition.new(:default)) }
166
+ @target_definition = TargetDefinition.new(:default, :exclusive => true)
167
+ @target_definition.user_project = UserProject.new
168
+ @target_definitions = { :default => @target_definition }
44
169
  instance_eval(&block)
45
170
  end
46
171
 
@@ -55,8 +180,73 @@ module Pod
55
180
  # platform :ios, :deployment_target => "4.0"
56
181
  #
57
182
  # If the deployment target requires it (< 4.3), armv6 will be added to ARCHS.
58
- def platform(platform = nil, options={})
59
- platform ? @platform = Platform.new(platform, options) : @platform
183
+ #
184
+ def platform(platform, options={})
185
+ @target_definition.platform = Platform.new(platform, options)
186
+ end
187
+
188
+ # Specifies the Xcode workspace that should contain all the projects.
189
+ #
190
+ # If no explicit Xcode workspace is specified and only **one** project exists
191
+ # in the same directory as the Podfile, then the name of that project is used
192
+ # as the workspace’s name.
193
+ #
194
+ # @example
195
+ #
196
+ # workspace 'MyWorkspace'
197
+ #
198
+ def workspace(path = nil)
199
+ if path
200
+ @workspace = config.project_root + (File.extname(path) == '.xcworkspace' ? path : "#{path}.xcworkspace")
201
+ elsif @workspace
202
+ @workspace
203
+ else
204
+ projects = @target_definitions.map { |_, td| td.user_project.path }.uniq
205
+ if projects.size == 1 && (xcodeproj = @target_definitions[:default].user_project.path)
206
+ config.project_root + "#{xcodeproj.basename('.xcodeproj')}.xcworkspace"
207
+ end
208
+ end
209
+ end
210
+
211
+ # Specifies the Xcode project that contains the target that the Pods library
212
+ # should be linked with.
213
+ #
214
+ # If no explicit project is specified, it will use the Xcode project of the
215
+ # parent target. If none of the target definitions specify an explicit project
216
+ # and there is only **one** project in the same directory as the Podfile then
217
+ # that project will be used.
218
+ #
219
+ # @example
220
+ #
221
+ # # Look for target to link with in an Xcode project called ‘MyProject.xcodeproj’.
222
+ # xcodeproj 'MyProject'
223
+ #
224
+ # target :test do
225
+ # # This Pods library links with a target in another project.
226
+ # xcodeproj 'TestProject'
227
+ # end
228
+ #
229
+ def xcodeproj(path, build_configurations = {})
230
+ @target_definition.user_project = UserProject.new(path, build_configurations)
231
+ end
232
+
233
+ # Specifies the target(s) in the user’s project that this Pods library
234
+ # should be linked in.
235
+ #
236
+ # If no explicit target is specified, then the Pods target will be linked
237
+ # with the first target in your project. So if you only have one target you
238
+ # do not need to specify the target to link with.
239
+ #
240
+ # @example
241
+ #
242
+ # # Link with a target called ‘MyApp’ (in the user's project).
243
+ # link_with 'MyApp'
244
+ #
245
+ # # Link with the targets in the user’s project called ‘MyApp’ and ‘MyOtherApp’.
246
+ # link_with ['MyApp', 'MyOtherApp']
247
+ #
248
+ def link_with(targets)
249
+ @target_definition.link_with = targets
60
250
  end
61
251
 
62
252
  # Specifies a dependency of the project.
@@ -156,8 +346,8 @@ module Pod
156
346
  @target_definition.target_dependencies << Dependency.new(*name_and_version_requirements, &block)
157
347
  end
158
348
 
159
- # Specifies that a BridgeSupport metadata should be generated from the
160
- # headers of all installed Pods.
349
+ # Specifies that a BridgeSupport metadata document should be generated from
350
+ # the headers of all installed Pods.
161
351
  #
162
352
  # This is for scripting languages such as MacRuby, Nu, and JSCocoa, which use
163
353
  # it to bridge types, functions, etc better.
@@ -193,7 +383,8 @@ module Pod
193
383
  # dependency (JSONKit).
194
384
  def target(name, options = {})
195
385
  parent = @target_definition
196
- @target_definitions[name] = @target_definition = TargetDefinition.new(name, options[:exclusive] ? nil : parent)
386
+ options[:parent] = parent
387
+ @target_definitions[name] = @target_definition = TargetDefinition.new(name, options)
197
388
  yield
198
389
  ensure
199
390
  @target_definition = parent
@@ -206,8 +397,8 @@ module Pod
206
397
  #
207
398
  # post_install do |installer|
208
399
  # installer.project.targets.each do |target|
209
- # target.buildConfigurations.each do |config|
210
- # config.buildSettings['GCC_ENABLE_OBJC_GC'] = 'supported'
400
+ # target.build_configurations.each do |config|
401
+ # config.build_settings['GCC_ENABLE_OBJC_GC'] = 'supported'
211
402
  # end
212
403
  # end
213
404
  # end
@@ -215,6 +406,19 @@ module Pod
215
406
  @post_install_callback = block
216
407
  end
217
408
 
409
+ # Specifies that the -fobjc-arc flag should be added to the OTHER_LD_FLAGS.
410
+ #
411
+ # This is used as a workaround for a compiler bug with non-ARC projects.
412
+ # (see https://github.com/CocoaPods/CocoaPods/issues/142)
413
+ #
414
+ # This was originally done automatically but libtool as of Xcode 4.3.2 no
415
+ # longer seems to support the -fobjc-arc flag. Therefore it now has to be
416
+ # enabled explicitly using this method.
417
+ #
418
+ # This may be removed in a future release.
419
+ def set_arc_compatibility_flag!
420
+ @set_arc_compatibility_flag = true
421
+ end
218
422
 
219
423
  # Not attributes
220
424
 
@@ -226,7 +430,7 @@ module Pod
226
430
  attr_reader :target_definitions
227
431
 
228
432
  def dependencies
229
- @target_definitions.values.map(&:target_dependencies).flatten
433
+ @target_definitions.values.map(&:target_dependencies).flatten.uniq
230
434
  end
231
435
 
232
436
  def dependency_by_top_level_spec_name(name)
@@ -237,15 +441,24 @@ module Pod
237
441
  @generate_bridge_support
238
442
  end
239
443
 
444
+ def set_arc_compatibility_flag?
445
+ @set_arc_compatibility_flag
446
+ end
447
+
448
+ def user_build_configurations
449
+ configs_array = @target_definitions.values.map { |td| td.user_project.build_configurations }
450
+ configs_array.inject({}) { |hash, config| hash.merge(config) }
451
+ end
452
+
240
453
  def post_install!(installer)
241
454
  @post_install_callback.call(installer) if @post_install_callback
242
455
  end
243
456
 
244
457
  def validate!
245
- lines = []
246
- lines << "* the `platform` attribute should be either `:osx` or `:ios`" unless @platform && [:osx, :ios].include?(@platform.name)
247
- lines << "* no dependencies were specified, which is, well, kinda pointless" if dependencies.empty?
248
- raise(Informative, (["The Podfile at `#{@defined_in_file}' is invalid:"] + lines).join("\n")) unless lines.empty?
458
+ #lines = []
459
+ #lines << "* the `platform` attribute should be either `:osx` or `:ios`" unless @platform && [:osx, :ios].include?(@platform.name)
460
+ #lines << "* no dependencies were specified, which is, well, kinda pointless" if dependencies.empty?
461
+ #raise(Informative, (["The Podfile at `#{@defined_in_file}' is invalid:"] + lines).join("\n")) unless lines.empty?
249
462
  end
250
463
  end
251
464
  end
@@ -0,0 +1,67 @@
1
+ require 'xcodeproj/project'
2
+ require 'xcodeproj/project/object/build_phase'
3
+
4
+ Xcodeproj::Project::Object::PBXCopyFilesBuildPhase.instance_eval do
5
+ def self.new_pod_dir(project, pod_name, path)
6
+ new(project, nil, {
7
+ "dstPath" => "Pods/#{path}",
8
+ "name" => "Copy #{pod_name} Public Headers",
9
+ })
10
+ end
11
+ end
12
+
13
+ module Pod
14
+ class Project < Xcodeproj::Project
15
+ def initialize(*)
16
+ super
17
+ main_group << groups.new('name' => 'Pods')
18
+ @user_build_configurations = []
19
+ end
20
+
21
+ def user_build_configurations=(user_build_configurations)
22
+ @user_build_configurations = user_build_configurations
23
+ # The configurations at the top level only need to exist, they don't hold
24
+ # any build settings themselves, that's left to `add_pod_target`.
25
+ user_build_configurations.each do |name, _|
26
+ unless build_configurations.map(&:name).include?(name)
27
+ build_configurations.new('name' => name)
28
+ end
29
+ end
30
+ end
31
+
32
+ # Shortcut access to the `Pods' PBXGroup.
33
+ def pods
34
+ groups.find { |g| g.name == 'Pods' } || groups.new({ 'name' => 'Pods' })
35
+ end
36
+
37
+ # Adds a group as child to the `Pods' group.
38
+ def add_pod_group(name)
39
+ pods.groups.new('name' => name)
40
+ end
41
+
42
+ def add_pod_target(name, platform)
43
+ target = targets.new_static_library(platform.name, name)
44
+
45
+ settings = {}
46
+ if platform.requires_legacy_ios_archs?
47
+ settings['ARCHS'] = "armv6 armv7"
48
+ end
49
+ if platform == :ios && platform.deployment_target
50
+ settings['IPHONEOS_DEPLOYMENT_TARGET'] = platform.deployment_target.to_s
51
+ end
52
+
53
+ target.build_settings('Debug').merge!(settings)
54
+ target.build_settings('Release').merge!(settings)
55
+
56
+ @user_build_configurations.each do |name, type|
57
+ unless target.build_configurations.map(&:name).include?(name)
58
+ config = target.build_configurations.new('name' => name)
59
+ # Copy the settings from either the Debug or the Release configuration.
60
+ config.build_settings = target.build_settings(type.to_s.capitalize).merge(settings)
61
+ end
62
+ end
63
+
64
+ target
65
+ end
66
+ end
67
+ end
@@ -1,51 +1,81 @@
1
+ require 'colored'
2
+
1
3
  module Pod
2
4
  class Resolver
3
- def initialize(specification, dependencies = nil)
4
- @specification, @dependencies = specification, dependencies || specification.dependencies
5
+ include Config::Mixin
6
+
7
+ attr_reader :podfile, :sandbox
8
+ attr_accessor :cached_sets, :cached_sources
9
+
10
+ def initialize(podfile, sandbox)
11
+ @podfile = podfile
12
+ @sandbox = sandbox
13
+ @cached_sets = {}
14
+ @cached_sources = Source::Aggregate.new
15
+ @log_indent = 0;
5
16
  end
6
17
 
7
18
  def resolve
8
- @sets, @loaded_spec_names, @specs = [], [], []
9
- find_dependency_sets(@specification, @dependencies)
10
- @specs.sort_by(&:name)
19
+ @specs = {}
20
+ targets_and_specs = {}
21
+
22
+ @podfile.target_definitions.values.each do |target_definition|
23
+ puts "\nResolving dependencies for target `#{target_definition.name}' (#{target_definition.platform})".green if config.verbose?
24
+ @loaded_specs = []
25
+ find_dependency_specs(@podfile, target_definition.dependencies, target_definition)
26
+ targets_and_specs[target_definition] = @specs.values_at(*@loaded_specs).sort_by(&:name)
27
+ end
28
+
29
+ @specs.values.sort_by(&:name)
30
+ targets_and_specs
11
31
  end
12
32
 
13
- def find_dependency_sets(specification, dependencies = nil)
14
- (dependencies || specification.dependencies).each do |dependency|
15
- set = find_dependency_set(dependency)
16
- set.required_by(specification)
17
- unless @loaded_spec_names.include?(dependency.name)
18
- # Get a reference to the spec that’s actually being loaded.
19
- # If it’s a subspec dependency, e.g. 'RestKit/Network', then
20
- # find that subspec.
21
- spec = set.specification
33
+ private
34
+
35
+ def find_cached_set(dependency, platform)
36
+ set_name = dependency.name.split('/').first
37
+ @cached_sets[set_name] ||= begin
38
+ if dependency.specification
39
+ Specification::Set::External.new(dependency.specification)
40
+ elsif external_source = dependency.external_source
41
+ # The platform isn't actually being used by the LocalPod instance
42
+ # that's being used behind the scenes, but passing it anyways for
43
+ # completeness sake.
44
+ specification = external_source.specification_from_sandbox(@sandbox, platform)
45
+ set = Specification::Set::External.new(specification)
22
46
  if dependency.subspec_dependency?
23
- spec = spec.subspec_by_name(dependency.name)
47
+ @cached_sets[dependency.top_level_spec_name] ||= set
24
48
  end
25
- validate_platform!(spec)
26
-
27
- # Ensure we don't resolve the same spec twice
28
- @loaded_spec_names << spec.name
29
- @specs << spec
30
- @sets << set unless @sets.include?(set)
31
-
32
- find_dependency_sets(spec)
49
+ set
50
+ else
51
+ @cached_sources.search(dependency)
33
52
  end
34
53
  end
35
54
  end
36
55
 
37
- def find_dependency_set(dependency)
38
- if external_spec = dependency.specification
39
- Specification::Set::External.new(external_spec)
40
- else
41
- Source.search(dependency)
56
+ def find_dependency_specs(dependent_specification, dependencies, target_definition)
57
+ @log_indent += 1
58
+ dependencies.each do |dependency|
59
+ puts ' ' * @log_indent + "- #{dependency}" if config.verbose?
60
+ set = find_cached_set(dependency, target_definition.platform)
61
+ set.required_by(dependent_specification)
62
+ # Ensure we don't resolve the same spec twice for one target
63
+ unless @loaded_specs.include?(dependency.name)
64
+ spec = set.specification_by_name(dependency.name)
65
+ @loaded_specs << spec.name
66
+ @specs[spec.name] = spec
67
+ spec.activate_platform(target_definition.platform)
68
+ # And recursively load the dependencies of the spec.
69
+ find_dependency_specs(spec, spec.dependencies, target_definition) if spec.dependencies
70
+ end
71
+ validate_platform!(spec || @specs[dependency.name], target_definition)
42
72
  end
73
+ @log_indent -= 1
43
74
  end
44
75
 
45
- def validate_platform!(spec)
46
- unless spec.platform.nil? || spec.platform == @specification.platform
47
- raise Informative, "The platform required by the Podfile (:#{@specification.platform}) " \
48
- "does not match that of #{spec} (:#{spec.platform})"
76
+ def validate_platform!(spec, target)
77
+ unless spec.available_platforms.any? { |platform| target.platform.supports?(platform) }
78
+ raise Informative, "[!] The platform of the target `#{target.name}' (#{target.platform}) is not compatible with `#{spec}' which has a minimun requirement of #{spec.available_platforms.join(' - ')}.".red
49
79
  end
50
80
  end
51
81
  end