cocoapods 0.5.1 → 0.6.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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