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