cocoapods 0.13.0 → 0.14.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.
@@ -41,11 +41,16 @@ module Pod
41
41
  @project_podfile ||= project_root + 'Podfile'
42
42
  end
43
43
 
44
+ def project_lockfile
45
+ @project_lockfile ||= project_root + 'Podfile.lock'
46
+ end
47
+
44
48
  def headers_symlink_root
45
49
  @headers_symlink_root ||= "#{project_pods_root}/Headers"
46
50
  end
47
51
 
48
- # Returns the spec at the pat returned from `project_podfile`.
52
+ # @return [Podfile] The Podfile to use for the current execution.
53
+ #
49
54
  def podfile
50
55
  @podfile ||= begin
51
56
  Podfile.from_file(project_podfile) if project_podfile.exist?
@@ -53,6 +58,14 @@ module Pod
53
58
  end
54
59
  attr_writer :podfile
55
60
 
61
+ # @return [Lockfile] The Lockfile to use for the current execution.
62
+ #
63
+ def lockfile
64
+ @lockfile ||= begin
65
+ Lockfile.from_file(project_lockfile) if project_lockfile.exist?
66
+ end
67
+ end
68
+
56
69
  module Mixin
57
70
  def config
58
71
  Config.instance
@@ -3,9 +3,9 @@ require 'cocoapods/open_uri'
3
3
  module Pod
4
4
  class Dependency < Gem::Dependency
5
5
 
6
- attr_reader :external_source, :head
6
+ attr_reader :head
7
7
  alias :head? :head
8
- attr_accessor :specification
8
+ attr_accessor :specification, :external_source
9
9
 
10
10
  def initialize(*name_and_version_requirements, &block)
11
11
  if name_and_version_requirements.empty? && block
@@ -40,7 +40,7 @@ module Pod
40
40
  end
41
41
 
42
42
  def ==(other)
43
- super && (@specification ? @specification == other.specification : @external_source == other.external_source)
43
+ super && (head? == other.head?) && (@specification ? @specification == other.specification : @external_source == other.external_source)
44
44
  end
45
45
 
46
46
  def subspec_dependency?
@@ -76,13 +76,14 @@ module Pod
76
76
  if external?
77
77
  version << @external_source.description
78
78
  elsif inline?
79
- version << "defined in Podfile"
79
+ version << 'defined in Podfile'
80
+ elsif head?
81
+ version << 'HEAD'
80
82
  elsif @version_requirements != Gem::Requirement.default
81
83
  version << @version_requirements.to_s
82
84
  end
83
85
  result = @name.dup
84
- result += " (#{version})" unless version.empty?
85
- result += " [HEAD]" if head?
86
+ result << " (#{version})" unless version.empty?
86
87
  result
87
88
  end
88
89
 
@@ -90,6 +91,10 @@ module Pod
90
91
  @external_source.specification_from_sandbox(sandbox, platform)
91
92
  end
92
93
 
94
+ def match_version?(version)
95
+ match?(name, version) && (version.head? == head?)
96
+ end
97
+
93
98
  # Taken from RubyGems 1.3.7
94
99
  unless public_method_defined?(:match?)
95
100
  def match?(spec_name, spec_version)
@@ -128,10 +133,13 @@ module Pod
128
133
 
129
134
  module ExternalSources
130
135
  def self.from_params(name, params)
136
+ return unless name && params
131
137
  if params.key?(:git)
132
138
  GitSource.new(name, params)
133
139
  elsif params.key?(:podspec)
134
140
  PodspecSource.new(name, params)
141
+ elsif params.key?(:local)
142
+ LocalSource.new(name, params)
135
143
  else
136
144
  raise Informative, "Unknown external source parameters for #{name}: #{params}"
137
145
  end
@@ -158,18 +166,22 @@ module Pod
158
166
 
159
167
  def specification_from_external(sandbox, platform)
160
168
  copy_external_source_into_sandbox(sandbox, platform)
161
- specification_from_local(sandbox, platform)
169
+ spec = specification_from_local(sandbox, platform)
170
+ raise Informative, "No podspec found for `#{name}' in #{description}" unless spec
171
+ spec
162
172
  end
163
173
 
164
- def ==(other_source)
165
- return if other_source.nil?
166
- name == other_source.name && params == other_source.params
174
+ def ==(other)
175
+ return if other.nil?
176
+ name == other.name && params == other.params
167
177
  end
168
178
  end
169
179
 
170
180
  class GitSource < AbstractExternalSource
171
181
  def copy_external_source_into_sandbox(sandbox, platform)
172
- puts " * Pre-downloading: '#{name}'" unless config.silent?
182
+ puts "-> Pre-downloading: '#{name}'" unless config.silent?
183
+ target = sandbox.root + name
184
+ target.rmtree if target.exist?
173
185
  downloader = Downloader.for_target(sandbox.root + name, @params)
174
186
  downloader.download
175
187
  if local_pod = sandbox.installed_pod_named(name, platform)
@@ -191,8 +203,10 @@ module Pod
191
203
  def copy_external_source_into_sandbox(sandbox, _)
192
204
  output_path = sandbox.root + "Local Podspecs/#{name}.podspec"
193
205
  output_path.dirname.mkpath
194
- puts " * Fetching podspec for `#{name}' from: #{@params[:podspec]}" unless config.silent?
195
- open(@params[:podspec]) do |io|
206
+ puts "-> Fetching podspec for `#{name}' from: #{@params[:podspec]}" unless config.silent?
207
+ path = @params[:podspec]
208
+ path = Pathname.new(path).expand_path if path.start_with?("~")
209
+ open(path) do |io|
196
210
  output_path.open('w') { |f| f << io.read }
197
211
  end
198
212
  end
@@ -201,6 +215,35 @@ module Pod
201
215
  "from `#{@params[:podspec]}'"
202
216
  end
203
217
  end
218
+
219
+ class LocalSource < AbstractExternalSource
220
+ def pod_spec_path
221
+ path = Pathname.new(@params[:local]).expand_path + "#{name}.podspec"
222
+ raise Informative, "No podspec found for `#{name}' in `#{@params[:local]}'" unless path.exist?
223
+ path
224
+ end
225
+
226
+ def copy_external_source_into_sandbox(sandbox, _)
227
+ output_path = sandbox.root + "Local Podspecs/#{name}.podspec"
228
+ output_path.dirname.mkpath
229
+ FileUtils.copy(pod_spec_path, output_path)
230
+ end
231
+
232
+ def specification_from_local(sandbox, platform)
233
+ specification_from_external(sandbox, platform)
234
+ end
235
+
236
+ def specification_from_external(sandbox, platform)
237
+ copy_external_source_into_sandbox(sandbox, platform)
238
+ spec = Specification.from_file(pod_spec_path)
239
+ spec.source = @params
240
+ spec
241
+ end
242
+
243
+ def description
244
+ "from `#{@params[:local]}'"
245
+ end
246
+ end
204
247
  end
205
248
  end
206
249
  end
@@ -79,6 +79,7 @@ module Pod
79
79
  git! "reset --hard HEAD"
80
80
  git! "clean -d -x -f"
81
81
  git! "pull origin master"
82
+ git! "fetch --tags"
82
83
  end
83
84
  end
84
85
 
@@ -3,12 +3,16 @@ module Pod
3
3
  class Subversion < Downloader
4
4
  executable :svn
5
5
 
6
+ def initialize(target_path, url, options)
7
+ @target_path, @url, @options = target_path, url, options
8
+ end
9
+
6
10
  def download
7
- svn! %|checkout "#{reference_url}" "#{target_path}"|
11
+ svn! %|export "#{reference_url}" "#{target_path}"|
8
12
  end
9
13
 
10
14
  def download_head
11
- svn! %|checkout "#{trunk_url}" "#{target_path}"|
15
+ svn! %|export "#{trunk_url}" "#{target_path}"|
12
16
  end
13
17
 
14
18
  def reference_url
@@ -7,19 +7,12 @@ module Pod
7
7
 
8
8
  include Config::Mixin
9
9
 
10
- attr_reader :sandbox
11
-
12
- def initialize(podfile)
13
- @podfile = podfile
14
- # FIXME: pass this into the installer as a parameter
15
- @sandbox = Sandbox.new(config.project_pods_root)
16
- @resolver = Resolver.new(@podfile, @sandbox)
17
- # TODO: remove in 0.7 (legacy support for config.ios? and config.osx?)
18
- config.podfile = podfile
19
- end
10
+ attr_reader :resolver, :sandbox, :lockfile
20
11
 
21
- def lock_file
22
- config.project_root + 'Podfile.lock'
12
+ def initialize(resolver)
13
+ @resolver = resolver
14
+ @podfile = resolver.podfile
15
+ @sandbox = resolver.sandbox
23
16
  end
24
17
 
25
18
  def project
@@ -29,7 +22,8 @@ module Pod
29
22
  pods.each do |pod|
30
23
  # Add all source files to the project grouped by pod
31
24
  pod.relative_source_files_by_spec.each do |spec, paths|
32
- group = @project.add_spec_group(spec.name)
25
+ parent_group = pod.local? ? @project.local_pods : @project.pods
26
+ group = @project.add_spec_group(pod.name, parent_group)
33
27
  paths.each do |path|
34
28
  group.files.new('path' => path.to_s)
35
29
  end
@@ -46,8 +40,17 @@ module Pod
46
40
  end.compact
47
41
  end
48
42
 
43
+ # Install the Pods. If the resolver indicated that a Pod should be installed
44
+ # and it exits, it is removed an then reinstalled. In any case if the Pod
45
+ # doesn't exits it is installed.
46
+ #
47
+ # @return [void]
48
+ #
49
49
  def install_dependencies!
50
- pods.each do |pod|
50
+ pods.sort_by { |pod| pod.top_specification.name.downcase }.each do |pod|
51
+ name = pod.top_specification.name
52
+ should_install = @resolver.should_install?(name) || !pod.exists?
53
+
51
54
  unless config.silent?
52
55
  marker = config.verbose ? "\n-> ".green : ''
53
56
  if subspec_name = pod.top_specification.preferred_dependency
@@ -55,15 +58,14 @@ module Pod
55
58
  else
56
59
  name = pod.to_s
57
60
  end
58
- name << " [HEAD]" if pod.top_specification.version.head?
59
- puts marker << ( pod.exists? ? "Using #{name}" : "Installing #{name}".green )
61
+ puts marker << ( should_install ? "Installing #{name}".green : "Using #{name}" )
60
62
  end
61
63
 
62
- download_pod(pod) unless pod.exists?
63
-
64
- # This will not happen if the pod existed before we started the install
65
- # process.
66
- if pod.downloaded?
64
+ if should_install
65
+ unless pod.downloaded?
66
+ pod.implode
67
+ download_pod(pod)
68
+ end
67
69
  # The docs need to be generated before cleaning because the
68
70
  # documentation is created for all the subspecs.
69
71
  generate_docs(pod)
@@ -100,12 +102,26 @@ module Pod
100
102
  end
101
103
  end
102
104
 
105
+ # @TODO: use the local pod implode
106
+ #
107
+ def remove_deleted_dependencies!
108
+ resolver.removed_pods.each do |pod_name|
109
+ marker = config.verbose ? "\n-> ".red : ''
110
+ path = sandbox.root + pod_name
111
+ puts marker << "Removing #{pod_name}".red
112
+ path.rmtree if path.exist?
113
+ end
114
+ end
115
+
103
116
  def install!
104
117
  @sandbox.prepare_for_install
105
118
 
106
119
  print_title "Resolving dependencies of: #{@podfile.defined_in_file}"
107
120
  specs_by_target
108
121
 
122
+ print_title "Removing deleted dependencies" unless resolver.removed_pods.empty?
123
+ remove_deleted_dependencies!
124
+
109
125
  print_title "Installing dependencies"
110
126
  install_dependencies!
111
127
 
@@ -119,15 +135,17 @@ module Pod
119
135
  generate_dummy_source(target_installer)
120
136
  end
121
137
 
122
- generate_lock_file!(specifications)
123
-
124
138
  puts "- Running post install hooks" if config.verbose?
125
139
  # Post install hooks run _before_ saving of project, so that they can alter it before saving.
126
140
  run_post_install_hooks
127
141
 
128
- puts "- Writing Xcode project file to `#{@sandbox.project_path}'\n\n" if config.verbose?
142
+ puts "- Writing Xcode project file to `#{@sandbox.project_path}'" if config.verbose?
129
143
  project.save_as(@sandbox.project_path)
130
144
 
145
+ puts "- Writing lockfile in `#{config.project_lockfile}'\n\n" if config.verbose?
146
+ @lockfile = Lockfile.generate(@podfile, specs_by_target.values.flatten)
147
+ @lockfile.write_to_disk(config.project_lockfile)
148
+
131
149
  UserProjectIntegrator.new(@podfile).integrate! if config.integrate_targets?
132
150
  end
133
151
 
@@ -143,44 +161,6 @@ module Pod
143
161
  @podfile.post_install!(self)
144
162
  end
145
163
 
146
- def generate_lock_file!(specs)
147
- lock_file.open('w') do |file|
148
- file.puts "PODS:"
149
-
150
- # Get list of [name, dependencies] pairs.
151
- pod_and_deps = specs.map do |spec|
152
- [spec.to_s, spec.dependencies.map(&:to_s).sort]
153
- end.uniq
154
-
155
- # Merge dependencies of ios and osx version of the same pod.
156
- tmp = {}
157
- pod_and_deps.each do |name, deps|
158
- if tmp[name]
159
- tmp[name].concat(deps).uniq!
160
- else
161
- tmp[name] = deps
162
- end
163
- end
164
- pod_and_deps = tmp
165
-
166
- # Sort by name and print
167
- pod_and_deps.sort_by(&:first).each do |name, deps|
168
- if deps.empty?
169
- file.puts " - #{name}"
170
- else
171
- file.puts " - #{name}:"
172
- deps.each { |dep| file.puts " - #{dep}" }
173
- end
174
- end
175
-
176
- file.puts
177
- file.puts "DEPENDENCIES:"
178
- @podfile.dependencies.map(&:to_s).sort.each do |dep|
179
- file.puts " - #{dep}"
180
- end
181
- end
182
- end
183
-
184
164
  def generate_dummy_source(target_installer)
185
165
  class_name_identifier = target_installer.target_definition.label
186
166
  dummy_source = Generator::DummySource.new(class_name_identifier)
@@ -206,7 +186,7 @@ module Pod
206
186
  # @return [Array<LocalPod>] A list of LocalPod instances for each
207
187
  # dependency that is not a download-only one.
208
188
  def pods
209
- pods_by_target.values.flatten
189
+ pods_by_target.values.flatten.uniq
210
190
  end
211
191
 
212
192
  def pods_by_target
@@ -215,7 +195,11 @@ module Pod
215
195
  specs_by_target.each do |target_definition, specs|
216
196
  @pods_by_spec[target_definition.platform] = {}
217
197
  result[target_definition] = specs.map do |spec|
218
- @sandbox.local_pod_for_spec(spec, target_definition.platform)
198
+ if spec.local?
199
+ LocalPod::LocalSourcedPod.new(spec, sandbox, target_definition.platform)
200
+ else
201
+ @sandbox.local_pod_for_spec(spec, target_definition.platform)
202
+ end
219
203
  end.uniq.compact
220
204
  end
221
205
  result
@@ -45,16 +45,18 @@ module Pod
45
45
  attr_accessor :downloaded
46
46
  alias_method :downloaded?, :downloaded
47
47
 
48
- # @param [Specification] specification
49
- # The first activated specification of the pod.
50
- # @param [Sandbox] sandbox
51
- # The sandbox where the files of the pod will be located.
52
- # @param [Platform] platform
53
- # The platform that will be used to build the pod.
48
+ # @param [Specification] specification The first activated specification
49
+ # of the pod.
50
+ #
51
+ # @param [Sandbox] sandbox The sandbox where the files of the
52
+ # pod will be located.
53
+ #
54
+ # @param [Platform] platform The platform that will be used to
55
+ # build the pod.
54
56
  #
55
57
  # @todo The local pod should be initialized with all the activated
56
- # specifications passed as an array, in order to be able to cache the
57
- # computed values. In other words, it should be immutable.
58
+ # specifications passed as an array, in order to be able to cache the
59
+ # computed values. In other words, it should be immutable.
58
60
  #
59
61
  def initialize(specification, sandbox, platform)
60
62
  @top_specification, @sandbox, @platform = specification.top_level_parent, sandbox, platform
@@ -93,12 +95,10 @@ module Pod
93
95
  end
94
96
 
95
97
  # @return [String] A string representation of the pod which indicates if
96
- # the pods comes from a local source.
98
+ # the pods comes from a local source.
97
99
  #
98
100
  def to_s
99
- result = top_specification.to_s
100
- result << " [LOCAL]" if top_specification.local?
101
- result
101
+ top_specification.to_s
102
102
  end
103
103
 
104
104
  # @return [String] The name of the Pod.
@@ -140,6 +140,10 @@ module Pod
140
140
  root.rmtree if exists?
141
141
  end
142
142
 
143
+ def local?
144
+ false
145
+ end
146
+
143
147
  # @!group Cleaning
144
148
 
145
149
  # Deletes any path that is not used by the pod.
@@ -508,5 +512,39 @@ module Pod
508
512
  Pathname.glob(pattern, File::FNM_CASEFOLD)
509
513
  end.flatten
510
514
  end
515
+
516
+ # A {LocalSourcedPod} is a {LocalPod} that interacts with the files of
517
+ # a folder controlled by the users. As such this class does not alter
518
+ # in any way the contents of the folder.
519
+ #
520
+ class LocalSourcedPod < LocalPod
521
+ def downloaded?
522
+ true
523
+ end
524
+
525
+ def create
526
+ # No ops
527
+ end
528
+
529
+ def root
530
+ @root ||= Pathname.new(@top_specification.source[:local]).expand_path
531
+ end
532
+
533
+ def implode
534
+ # No ops
535
+ end
536
+
537
+ def clean!
538
+ # No ops
539
+ end
540
+
541
+ def to_s
542
+ super + " [LOCAL]"
543
+ end
544
+
545
+ def local?
546
+ true
547
+ end
548
+ end
511
549
  end
512
550
  end