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.
- data/CHANGELOG.md +97 -16
- data/lib/cocoapods.rb +2 -1
- data/lib/cocoapods/command.rb +46 -19
- data/lib/cocoapods/command/install.rb +11 -12
- data/lib/cocoapods/command/linter.rb +3 -1
- data/lib/cocoapods/command/outdated.rb +51 -0
- data/lib/cocoapods/command/push.rb +6 -6
- data/lib/cocoapods/command/setup.rb +1 -1
- data/lib/cocoapods/command/spec.rb +1 -1
- data/lib/cocoapods/command/update.rb +21 -0
- data/lib/cocoapods/config.rb +14 -1
- data/lib/cocoapods/dependency.rb +56 -13
- data/lib/cocoapods/downloader/git.rb +1 -0
- data/lib/cocoapods/downloader/subversion.rb +6 -2
- data/lib/cocoapods/installer.rb +48 -64
- data/lib/cocoapods/local_pod.rb +50 -12
- data/lib/cocoapods/lockfile.rb +267 -0
- data/lib/cocoapods/podfile.rb +4 -0
- data/lib/cocoapods/project.rb +9 -4
- data/lib/cocoapods/resolver.rb +164 -20
- data/lib/cocoapods/specification.rb +11 -13
- data/lib/cocoapods/specification/set.rb +10 -13
- data/lib/cocoapods/version.rb +19 -2
- metadata +7 -4
data/lib/cocoapods/config.rb
CHANGED
@@ -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
|
-
#
|
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
|
data/lib/cocoapods/dependency.rb
CHANGED
@@ -3,9 +3,9 @@ require 'cocoapods/open_uri'
|
|
3
3
|
module Pod
|
4
4
|
class Dependency < Gem::Dependency
|
5
5
|
|
6
|
-
attr_reader :
|
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 <<
|
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
|
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 ==(
|
165
|
-
return if
|
166
|
-
name ==
|
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 "
|
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 "
|
195
|
-
|
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
|
@@ -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! %|
|
11
|
+
svn! %|export "#{reference_url}" "#{target_path}"|
|
8
12
|
end
|
9
13
|
|
10
14
|
def download_head
|
11
|
-
svn! %|
|
15
|
+
svn! %|export "#{trunk_url}" "#{target_path}"|
|
12
16
|
end
|
13
17
|
|
14
18
|
def reference_url
|
data/lib/cocoapods/installer.rb
CHANGED
@@ -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
|
22
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
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}'
|
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
|
-
|
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
|
data/lib/cocoapods/local_pod.rb
CHANGED
@@ -45,16 +45,18 @@ module Pod
|
|
45
45
|
attr_accessor :downloaded
|
46
46
|
alias_method :downloaded?, :downloaded
|
47
47
|
|
48
|
-
# @param [Specification] specification
|
49
|
-
#
|
50
|
-
#
|
51
|
-
#
|
52
|
-
#
|
53
|
-
#
|
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
|
-
#
|
57
|
-
#
|
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
|
-
#
|
98
|
+
# the pods comes from a local source.
|
97
99
|
#
|
98
100
|
def to_s
|
99
|
-
|
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
|