cocoapods 1.0.0.beta.6 → 1.0.0.beta.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +46 -0
- data/lib/cocoapods.rb +2 -1
- data/lib/cocoapods/command.rb +1 -1
- data/lib/cocoapods/command/init.rb +4 -4
- data/lib/cocoapods/command/install.rb +1 -1
- data/lib/cocoapods/command/inter_process_communication.rb +3 -3
- data/lib/cocoapods/command/list.rb +1 -1
- data/lib/cocoapods/command/outdated.rb +1 -1
- data/lib/cocoapods/command/repo/add.rb +1 -1
- data/lib/cocoapods/command/repo/lint.rb +6 -6
- data/lib/cocoapods/command/repo/list.rb +2 -2
- data/lib/cocoapods/command/repo/push.rb +13 -15
- data/lib/cocoapods/command/repo/update.rb +1 -1
- data/lib/cocoapods/command/setup.rb +2 -2
- data/lib/cocoapods/command/spec.rb +1 -1
- data/lib/cocoapods/config.rb +5 -0
- data/lib/cocoapods/core_overrides.rb +1 -0
- data/lib/cocoapods/downloader.rb +5 -18
- data/lib/cocoapods/downloader/request.rb +1 -10
- data/lib/cocoapods/gem_version.rb +1 -1
- data/lib/cocoapods/generator/copy_resources_script.rb +17 -17
- data/lib/cocoapods/generator/embed_frameworks_script.rb +2 -2
- data/lib/cocoapods/generator/info_plist_file.rb +1 -0
- data/lib/cocoapods/installer.rb +3 -1
- data/lib/cocoapods/installer/analyzer.rb +4 -4
- data/lib/cocoapods/installer/target_installer/pod_target_installer.rb +1 -1
- data/lib/cocoapods/resolver.rb +9 -6
- data/lib/cocoapods/sandbox/path_list.rb +1 -1
- data/lib/cocoapods/sources_manager.rb +42 -539
- data/lib/cocoapods/user_interface.rb +4 -0
- data/lib/cocoapods/user_interface/error_report.rb +1 -1
- data/lib/cocoapods/validator.rb +1 -1
- metadata +26 -55
@@ -96,8 +96,8 @@ module Pod
|
|
96
96
|
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
97
97
|
# Use the current code_sign_identitiy
|
98
98
|
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
99
|
-
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements \\"$1\\""
|
100
|
-
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} --preserve-metadata=identifier,entitlements "$1"
|
99
|
+
echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \\"$1\\""
|
100
|
+
/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
|
101
101
|
fi
|
102
102
|
}
|
103
103
|
|
@@ -116,6 +116,7 @@ module Pod
|
|
116
116
|
}
|
117
117
|
|
118
118
|
info['CFBundleExecutable'] = '${EXECUTABLE_NAME}' if bundle_package_type != :bndl
|
119
|
+
info['CFBundleVersion'] = '1' if bundle_package_type == :bndl
|
119
120
|
info['UIRequiredDeviceCapabilities'] = %w(arm64) if target.platform.name == :tvos
|
120
121
|
|
121
122
|
info
|
data/lib/cocoapods/installer.rb
CHANGED
@@ -249,7 +249,9 @@ module Pod
|
|
249
249
|
|
250
250
|
remainder = whitelisted_configs - all_user_configurations
|
251
251
|
unless remainder.empty?
|
252
|
-
raise Informative,
|
252
|
+
raise Informative,
|
253
|
+
"Unknown #{'configuration'.pluralize(remainder.size)} whitelisted: #{remainder.sort.to_sentence}. " \
|
254
|
+
"CocoaPods found #{all_user_configurations.sort.to_sentence}, did you mean one of these?"
|
253
255
|
end
|
254
256
|
end
|
255
257
|
|
@@ -216,8 +216,8 @@ module Pod
|
|
216
216
|
#
|
217
217
|
def update_repositories
|
218
218
|
sources.each do |source|
|
219
|
-
if
|
220
|
-
|
219
|
+
if source.git?
|
220
|
+
config.sources_manager.update(source.name)
|
221
221
|
else
|
222
222
|
UI.message "Skipping `#{source.name}` update because the repository is not a git source repository."
|
223
223
|
end
|
@@ -628,7 +628,7 @@ module Pod
|
|
628
628
|
#
|
629
629
|
# When no explicit Podfile sources are defined, this defaults to the
|
630
630
|
# master spec repository.
|
631
|
-
# available sources ({
|
631
|
+
# available sources ({config.sources_manager.all}).
|
632
632
|
#
|
633
633
|
# @return [Array<Source>] the sources to be used in finding
|
634
634
|
# specifications, as specified by the {#podfile} or all sources.
|
@@ -650,7 +650,7 @@ module Pod
|
|
650
650
|
end
|
651
651
|
|
652
652
|
sources.uniq.map do |source_url|
|
653
|
-
|
653
|
+
config.sources_manager.find_or_create_source_with_url(source_url)
|
654
654
|
end
|
655
655
|
end
|
656
656
|
end
|
@@ -177,7 +177,7 @@ module Pod
|
|
177
177
|
c.build_settings['PRODUCT_NAME'] = bundle_name
|
178
178
|
relative_info_plist_path = info_plist_path.relative_path_from(sandbox.root)
|
179
179
|
c.build_settings['INFOPLIST_FILE'] = relative_info_plist_path.to_s
|
180
|
-
c.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir
|
180
|
+
c.build_settings['CONFIGURATION_BUILD_DIR'] = target.configuration_build_dir('$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)')
|
181
181
|
|
182
182
|
# Set the correct device family for this bundle, based on the platform
|
183
183
|
device_family_by_platform = {
|
data/lib/cocoapods/resolver.rb
CHANGED
@@ -350,7 +350,7 @@ module Pod
|
|
350
350
|
#
|
351
351
|
def aggregate_for_dependency(dependency)
|
352
352
|
if dependency && dependency.podspec_repo
|
353
|
-
return
|
353
|
+
return Config.instance.sources_manager.aggregate_for_dependency(dependency)
|
354
354
|
else
|
355
355
|
@aggregate ||= Source::Aggregate.new(sources)
|
356
356
|
end
|
@@ -420,11 +420,14 @@ module Pod
|
|
420
420
|
elsif !conflict.existing
|
421
421
|
conflict.requirements.values.flatten.each do |r|
|
422
422
|
if search_for(r).empty?
|
423
|
-
# There
|
424
|
-
message << "\n\nNone of
|
425
|
-
"\nYou have either
|
426
|
-
|
427
|
-
|
423
|
+
# There are no existing specification inside any of the spec repos with given requirements.
|
424
|
+
message << "\n\nNone of your spec sources contain a spec satisfying the dependency: `#{r}`." \
|
425
|
+
"\n\nYou have either:" \
|
426
|
+
"\n * out-of-date source repos which you can update with `pod repo update`." \
|
427
|
+
"\n * mistyped the name or version." \
|
428
|
+
"\n * not added the source repo that hosts the Podspec to your Podfile." \
|
429
|
+
"\n\nNote: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default."
|
430
|
+
|
428
431
|
else
|
429
432
|
message << "\n\nSpecs satisfying the `#{r}` dependency were found, " \
|
430
433
|
'but they required a higher minimum deployment target.'
|
@@ -49,7 +49,7 @@ module Pod
|
|
49
49
|
end
|
50
50
|
root_length = root.to_s.length + 1
|
51
51
|
escaped_root = escape_path_for_glob(root)
|
52
|
-
paths = Dir.glob(escaped_root + '**/*', File::FNM_DOTMATCH)
|
52
|
+
paths = Dir.glob(escaped_root + '**/*', File::FNM_DOTMATCH).sort_by(&:upcase)
|
53
53
|
absolute_dirs = paths.select { |path| File.directory?(path) }
|
54
54
|
relative_dirs = absolute_dirs.map { |p| p[root_length..-1] }
|
55
55
|
absolute_paths = paths.reject { |p| p == "#{root}/." || p == "#{root}/.." }
|
@@ -1,49 +1,8 @@
|
|
1
|
-
|
2
|
-
# Manages all the sources known to the running CocoaPods Instance.
|
3
|
-
#
|
4
|
-
class SourcesManager
|
5
|
-
class << self
|
6
|
-
include Config::Mixin
|
7
|
-
|
8
|
-
# @return [Source::Aggregate] The aggregate of all the sources with the
|
9
|
-
# known Pods.
|
10
|
-
#
|
11
|
-
def aggregate
|
12
|
-
return Source::Aggregate.new([]) unless config.repos_dir.exist?
|
13
|
-
dirs = config.repos_dir.children.select(&:directory?)
|
14
|
-
aggregate_with_repos(dirs)
|
15
|
-
end
|
16
|
-
|
17
|
-
# @return [Source::Aggregate] The aggregate of the sources from repos.
|
18
|
-
#
|
19
|
-
# @param [Dependency] dependency
|
20
|
-
# The dependency for which to find or build the appropriate.
|
21
|
-
# aggregate. If the dependency specifies a source podspec repo
|
22
|
-
# then only that source will be used, otherwise all sources
|
23
|
-
# will be used.
|
24
|
-
#
|
25
|
-
def aggregate_for_dependency(dependency)
|
26
|
-
if dependency.podspec_repo
|
27
|
-
source = source_with_url(dependency.podspec_repo)
|
28
|
-
raise StandardError, '[Bug] Failed to find known source with the URL ' \
|
29
|
-
"#{dependency.podspec_repo.inspect}" if source.nil?
|
30
|
-
|
31
|
-
aggregate_with_repos([source_dir(source.name)])
|
32
|
-
else
|
33
|
-
aggregate
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
# @return [Array<Source>] The list of the sources with the given names.
|
38
|
-
#
|
39
|
-
# @param [Array<#to_s>] names
|
40
|
-
# The names of the sources.
|
41
|
-
#
|
42
|
-
def sources(names)
|
43
|
-
dirs = names.map { |name| source_dir(name) }
|
44
|
-
dirs.map { |repo| source_from_path(repo) }
|
45
|
-
end
|
1
|
+
require 'cocoapods-core/source'
|
46
2
|
|
3
|
+
module Pod
|
4
|
+
class Source
|
5
|
+
class Manager
|
47
6
|
# Returns the source whose {Source#url} is equal to `url`, adding the repo
|
48
7
|
# in a manner similarly to `pod repo add` if it is not found.
|
49
8
|
#
|
@@ -66,16 +25,21 @@ module Pod
|
|
66
25
|
else
|
67
26
|
Command::Repo::Add.parse([name, url]).run
|
68
27
|
end
|
69
|
-
rescue Informative
|
70
|
-
|
71
|
-
"named `#{name}`.\
|
28
|
+
rescue Informative => e
|
29
|
+
message = "Unable to add a source with url `#{url}` " \
|
30
|
+
"named `#{name}`.\n"
|
31
|
+
message << "(#{e})\n" if Config.instance.verbose?
|
32
|
+
message << 'You can try adding it manually in ' \
|
72
33
|
'`~/.cocoapods/repos` or via `pod repo add`.'
|
34
|
+
raise Informative, message
|
73
35
|
ensure
|
74
36
|
UI.title_level = previous_title_level
|
75
37
|
end
|
76
38
|
source = source_with_url(url)
|
77
39
|
end
|
78
40
|
|
41
|
+
raise "Unable to create a source with URL #{url}" unless source
|
42
|
+
|
79
43
|
source
|
80
44
|
end
|
81
45
|
|
@@ -93,219 +57,14 @@ module Pod
|
|
93
57
|
find_or_create_source_with_url(name_or_url)
|
94
58
|
end
|
95
59
|
|
96
|
-
# @return [Array<Source>] The list of all the sources known to this
|
97
|
-
# installation of CocoaPods.
|
98
|
-
#
|
99
|
-
def all
|
100
|
-
return [] unless config.repos_dir.exist?
|
101
|
-
dirs = config.repos_dir.children.select(&:directory?)
|
102
|
-
dirs.map { |repo| source_from_path(repo) }
|
103
|
-
end
|
104
|
-
|
105
|
-
# @return [Array<Source>] The CocoaPods Master Repo source.
|
106
|
-
#
|
107
|
-
def master
|
108
|
-
sources(['master']).select { |s| s.repo.directory? }
|
109
|
-
end
|
110
|
-
|
111
|
-
# Search the appropriate sources to match the set for the given dependency.
|
112
|
-
#
|
113
|
-
# @return [Set, nil] a set for a given dependency including all the
|
114
|
-
# {Source} that contain the Pod. If no sources containing the
|
115
|
-
# Pod where found it returns nil.
|
116
|
-
#
|
117
|
-
# @raise If no source can be found that includes the dependency.
|
118
|
-
#
|
119
|
-
def search(dependency)
|
120
|
-
aggregate_for_dependency(dependency).search(dependency)
|
121
|
-
end
|
122
|
-
|
123
|
-
# Search all the sources with the given search term.
|
124
|
-
#
|
125
|
-
# @param [String] query
|
126
|
-
# The search term.
|
127
|
-
#
|
128
|
-
# @param [Bool] full_text_search
|
129
|
-
# Whether the search should be limited to the name of the Pod or
|
130
|
-
# should include also the author, the summary, and the
|
131
|
-
# description.
|
132
|
-
#
|
133
|
-
# @raise If no source including the set can be found.
|
134
|
-
#
|
135
|
-
# @return [Array<Set>] The sets that contain the search term.
|
136
|
-
#
|
137
|
-
def search_by_name(query, full_text_search = false)
|
138
|
-
query_word_regexps = query.split.map { |word| /#{word}/i }
|
139
|
-
if full_text_search
|
140
|
-
query_word_results_hash = {}
|
141
|
-
updated_search_index.each_value do |word_spec_hash|
|
142
|
-
word_spec_hash.each_pair do |word, spec_symbols|
|
143
|
-
query_word_regexps.each do |query_word_regexp|
|
144
|
-
set = (query_word_results_hash[query_word_regexp] ||= Set.new)
|
145
|
-
set.merge(spec_symbols) if word =~ query_word_regexp
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
found_set_symbols = query_word_results_hash.values.reduce(:&)
|
150
|
-
found_set_symbols ||= []
|
151
|
-
sets = found_set_symbols.map do |symbol|
|
152
|
-
aggregate.representative_set(symbol.to_s)
|
153
|
-
end
|
154
|
-
# Remove nil values because representative_set return nil if no pod is found in any of the sources.
|
155
|
-
sets.compact!
|
156
|
-
else
|
157
|
-
sets = aggregate.search_by_name(query, false)
|
158
|
-
end
|
159
|
-
if sets.empty?
|
160
|
-
extra = ', author, summary, or description' if full_text_search
|
161
|
-
raise Informative, "Unable to find a pod with name#{extra}" \
|
162
|
-
"matching `#{query}`"
|
163
|
-
end
|
164
|
-
sorted_sets(sets, query_word_regexps)
|
165
|
-
end
|
166
|
-
|
167
|
-
# Returns given set array by sorting it in-place.
|
168
|
-
#
|
169
|
-
# @param [Array<Set>] sets
|
170
|
-
# Array of sets to be sorted.
|
171
|
-
#
|
172
|
-
# @param [Array<Regexp>] query_word_regexps
|
173
|
-
# Array of regexp objects for user query.
|
174
|
-
#
|
175
|
-
# @return [Array<Set>] Given sets parameter itself after sorting it in-place.
|
176
|
-
#
|
177
|
-
def sorted_sets(sets, query_word_regexps)
|
178
|
-
sets.sort_by! do |set|
|
179
|
-
pre_match_length = nil
|
180
|
-
found_query_index = nil
|
181
|
-
found_query_count = 0
|
182
|
-
query_word_regexps.each_with_index do |q, idx|
|
183
|
-
if (m = set.name.match(/#{q}/i))
|
184
|
-
pre_match_length ||= (m.pre_match.length)
|
185
|
-
found_query_index ||= idx
|
186
|
-
found_query_count += 1
|
187
|
-
end
|
188
|
-
end
|
189
|
-
pre_match_length ||= 1000
|
190
|
-
found_query_index ||= 1000
|
191
|
-
[-found_query_count, pre_match_length, found_query_index, set.name.downcase]
|
192
|
-
end
|
193
|
-
sets
|
194
|
-
end
|
195
|
-
|
196
|
-
# Returns the search data. If a saved search data exists, retrieves it from file and returns it.
|
197
|
-
# Else, creates the search data from scratch, saves it to file system, and returns it.
|
198
|
-
# Search data is grouped by source repos. For each source, it contains a hash where keys are words
|
199
|
-
# and values are the pod names containing corresponding word.
|
200
|
-
#
|
201
|
-
# For each source, list of unique words are generated from the following spec information.
|
202
|
-
# - version
|
203
|
-
# - summary
|
204
|
-
# - description
|
205
|
-
# - authors
|
206
|
-
#
|
207
|
-
# @return [Hash{String => Hash{String => Array<String>}}] The up to date search data.
|
208
|
-
#
|
209
|
-
def updated_search_index
|
210
|
-
index = stored_search_index || {}
|
211
|
-
all.each do |source|
|
212
|
-
source_name = source.name
|
213
|
-
unless index[source_name]
|
214
|
-
UI.print "Creating search index for spec repo '#{source_name}'.."
|
215
|
-
index[source_name] = aggregate.generate_search_index_for_source(source)
|
216
|
-
UI.puts ' Done!'
|
217
|
-
end
|
218
|
-
end
|
219
|
-
save_search_index(index)
|
220
|
-
index
|
221
|
-
end
|
222
|
-
|
223
|
-
# Returns the search data stored in the file system.
|
224
|
-
# If existing data in the file system is not valid, returns nil.
|
225
|
-
#
|
226
|
-
def stored_search_index
|
227
|
-
unless @updated_search_index
|
228
|
-
if search_index_path.exist?
|
229
|
-
require 'json'
|
230
|
-
index = JSON.parse(search_index_path.read)
|
231
|
-
if index && index.is_a?(Hash) # TODO: should we also check if hash has correct hierarchy?
|
232
|
-
return @updated_search_index = index
|
233
|
-
end
|
234
|
-
end
|
235
|
-
@updated_search_index = nil
|
236
|
-
end
|
237
|
-
@updated_search_index
|
238
|
-
end
|
239
|
-
|
240
|
-
# Stores given search data in the file system.
|
241
|
-
# @param [Hash] index
|
242
|
-
# Index to be saved in file system
|
243
|
-
#
|
244
|
-
def save_search_index(index)
|
245
|
-
require 'json'
|
246
|
-
@updated_search_index = index
|
247
|
-
search_index_path.open('w') do |io|
|
248
|
-
io.write(@updated_search_index.to_json)
|
249
|
-
end
|
250
|
-
end
|
251
|
-
|
252
|
-
# Allows to clear the search index.
|
253
|
-
#
|
254
|
-
attr_writer :updated_search_index
|
255
|
-
|
256
60
|
# @return [Pathname] The path where the search index should be stored.
|
257
61
|
#
|
258
62
|
def search_index_path
|
259
|
-
Config.instance.search_index_file
|
63
|
+
@search_index_path ||= Config.instance.search_index_file
|
260
64
|
end
|
261
65
|
|
262
66
|
# @!group Updating Sources
|
263
67
|
|
264
|
-
extend Executable
|
265
|
-
executable :git
|
266
|
-
|
267
|
-
# Updates the stored search index if there are changes in spec repos while updating them.
|
268
|
-
# Update is performed incrementally. Only the changed pods' search data is re-generated and updated.
|
269
|
-
# @param [Hash{Source => Array<String>}] changed_spec_paths
|
270
|
-
# A hash containing changed specification paths for each source.
|
271
|
-
#
|
272
|
-
def update_search_index_if_needed(changed_spec_paths)
|
273
|
-
search_index = stored_search_index
|
274
|
-
return unless search_index
|
275
|
-
changed_spec_paths.each_pair do |source, spec_paths|
|
276
|
-
index_for_source = search_index[source.name]
|
277
|
-
next unless index_for_source && spec_paths.length > 0
|
278
|
-
updated_pods = source.pods_for_specification_paths(spec_paths)
|
279
|
-
|
280
|
-
new_index = aggregate.generate_search_index_for_changes_in_source(source, spec_paths)
|
281
|
-
# First traverse search_index and update existing words
|
282
|
-
# Removed traversed words from new_index after adding to search_index,
|
283
|
-
# so that only non existing words will remain in new_index after enumeration completes.
|
284
|
-
index_for_source.each_pair do |word, _|
|
285
|
-
if new_index[word]
|
286
|
-
index_for_source[word] |= new_index[word]
|
287
|
-
else
|
288
|
-
index_for_source[word] -= updated_pods
|
289
|
-
end
|
290
|
-
end
|
291
|
-
# Now add non existing words remained in new_index to search_index
|
292
|
-
index_for_source.merge!(new_index)
|
293
|
-
end
|
294
|
-
save_search_index(search_index)
|
295
|
-
end
|
296
|
-
|
297
|
-
# Updates search index for changed pods in background
|
298
|
-
# @param [Hash{Source => Array<String>}] changed_spec_paths
|
299
|
-
# A hash containing changed specification paths for each source.
|
300
|
-
#
|
301
|
-
def update_search_index_if_needed_in_background(changed_spec_paths)
|
302
|
-
Process.fork do
|
303
|
-
Process.daemon
|
304
|
-
update_search_index_if_needed(changed_spec_paths)
|
305
|
-
exit
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
68
|
# Updates the local clone of the spec-repo with the given name or of all
|
310
69
|
# the git repos if the name is omitted.
|
311
70
|
#
|
@@ -327,298 +86,14 @@ module Pod
|
|
327
86
|
UI.section "Updating spec repo `#{source.name}`" do
|
328
87
|
changed_source_paths = source.update(show_output)
|
329
88
|
changed_spec_paths[source] = changed_source_paths if changed_source_paths.count > 0
|
330
|
-
|
89
|
+
source.verify_compatibility!
|
331
90
|
end
|
332
91
|
end
|
333
92
|
# Perform search index update operation in background.
|
334
93
|
update_search_index_if_needed_in_background(changed_spec_paths)
|
335
94
|
end
|
336
|
-
|
337
|
-
# Returns whether a source is a GIT repo.
|
338
|
-
#
|
339
|
-
# @param [Pathname] dir
|
340
|
-
# The directory where the source is stored.
|
341
|
-
#
|
342
|
-
# @return [Bool] Whether the given source is a GIT repo.
|
343
|
-
#
|
344
|
-
def git_repo?(dir)
|
345
|
-
Dir.chdir(dir) do
|
346
|
-
Executable.capture_command('git', %w(rev-parse), :capture => :none).success?
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
# Checks the version information of the source with the given directory.
|
351
|
-
# It raises if the source is not compatible and if there is CocoaPods
|
352
|
-
# update it informs the user.
|
353
|
-
#
|
354
|
-
# @param [Pathname] dir
|
355
|
-
# The directory where the source is stored.
|
356
|
-
#
|
357
|
-
# @raise If the source is not compatible.
|
358
|
-
#
|
359
|
-
# @return [void]
|
360
|
-
#
|
361
|
-
def check_version_information(dir)
|
362
|
-
versions = version_information(dir)
|
363
|
-
unless repo_compatible?(dir)
|
364
|
-
min = versions['min']
|
365
|
-
max = versions['max']
|
366
|
-
version_msg = (min == max) ? min : "#{min} - #{max}"
|
367
|
-
raise Informative, "The `#{dir.basename}` repo requires " \
|
368
|
-
"CocoaPods #{version_msg} (currently using #{Pod::VERSION})\n".red +
|
369
|
-
'Update CocoaPods, or checkout the appropriate tag in the repo.'
|
370
|
-
end
|
371
|
-
|
372
|
-
if config.new_version_message? && cocoapods_update?(versions)
|
373
|
-
last = versions['last']
|
374
|
-
rc = Gem::Version.new(last).prerelease?
|
375
|
-
install_message = needs_sudo? ? 'sudo ' : ''
|
376
|
-
install_message << 'gem install cocoapods'
|
377
|
-
install_message << ' --pre' if rc
|
378
|
-
message = [
|
379
|
-
"CocoaPods #{last} is available.".green,
|
380
|
-
"To update use: `#{install_message}`".green,
|
381
|
-
("[!] This is a test version we'd love you to try.".yellow if rc),
|
382
|
-
("Until we reach version 1.0 the features of CocoaPods can and will change.\n" \
|
383
|
-
'We strongly recommend that you use the latest version at all times.'.yellow unless rc),
|
384
|
-
'',
|
385
|
-
'For more information, see https://blog.cocoapods.org ' \
|
386
|
-
'and the CHANGELOG for this version at ' \
|
387
|
-
"https://github.com/CocoaPods/CocoaPods/releases/tag/#{last}".green,
|
388
|
-
'',
|
389
|
-
].compact.join("\n")
|
390
|
-
UI.puts("\n#{message}\n")
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
# Returns whether a source is compatible with the current version of
|
395
|
-
# CocoaPods.
|
396
|
-
#
|
397
|
-
# @param [Pathname] dir
|
398
|
-
# The directory where the source is stored.
|
399
|
-
#
|
400
|
-
# @return [Bool] whether the source is compatible.
|
401
|
-
#
|
402
|
-
def repo_compatible?(dir)
|
403
|
-
versions = version_information(dir)
|
404
|
-
|
405
|
-
min = versions['min']
|
406
|
-
max = versions['max']
|
407
|
-
bin_version = Gem::Version.new(Pod::VERSION)
|
408
|
-
supports_min = !min || bin_version >= Gem::Version.new(min)
|
409
|
-
supports_max = !max || bin_version <= Gem::Version.new(max)
|
410
|
-
supports_min && supports_max
|
411
|
-
end
|
412
|
-
|
413
|
-
# Checks whether there is a CocoaPods given the version information of a
|
414
|
-
# repo.
|
415
|
-
#
|
416
|
-
# @param [Hash] version_information
|
417
|
-
# The version information of a repository.
|
418
|
-
#
|
419
|
-
# @return [Bool] whether there is an update.
|
420
|
-
#
|
421
|
-
def cocoapods_update?(version_information)
|
422
|
-
version = version_information['last']
|
423
|
-
version && Gem::Version.new(version) > Gem::Version.new(Pod::VERSION)
|
424
|
-
end
|
425
|
-
|
426
|
-
# Returns the contents of the `CocoaPods-version.yml` file, which stores
|
427
|
-
# information about CocoaPods versions.
|
428
|
-
#
|
429
|
-
# This file is a hash with the following keys:
|
430
|
-
#
|
431
|
-
# - last: the last version of CocoaPods known to the source.
|
432
|
-
# - min: the minimum version of CocoaPods supported by the source.
|
433
|
-
# - max: the maximum version of CocoaPods supported by the source.
|
434
|
-
#
|
435
|
-
# @param [Pathname] dir
|
436
|
-
# The directory where the source is stored.
|
437
|
-
#
|
438
|
-
# @return [Hash] the versions information from the repo.
|
439
|
-
#
|
440
|
-
def version_information(dir)
|
441
|
-
require 'yaml'
|
442
|
-
yaml_file = dir + 'CocoaPods-version.yml'
|
443
|
-
return {} unless yaml_file.exist?
|
444
|
-
begin
|
445
|
-
YAMLHelper.load_file(yaml_file)
|
446
|
-
rescue Informative
|
447
|
-
raise Informative, "There was an error reading '#{yaml_file}'.\n" \
|
448
|
-
'Please consult https://blog.cocoapods.org/' \
|
449
|
-
'Repairing-Our-Broken-Specs-Repository/ ' \
|
450
|
-
'for more information.'
|
451
|
-
end
|
452
|
-
end
|
453
|
-
|
454
|
-
# @!group Master repo
|
455
|
-
|
456
|
-
# @return [Pathname] The path of the master repo.
|
457
|
-
#
|
458
|
-
def master_repo_dir
|
459
|
-
config.repos_dir + 'master'
|
460
|
-
end
|
461
|
-
|
462
|
-
# @return [Bool] Checks if the master repo is usable.
|
463
|
-
#
|
464
|
-
# @note Note this is used to automatically setup the master repo if
|
465
|
-
# needed.
|
466
|
-
#
|
467
|
-
def master_repo_functional?
|
468
|
-
master_repo_dir.exist? && repo_compatible?(master_repo_dir)
|
469
|
-
end
|
470
|
-
|
471
|
-
private
|
472
|
-
|
473
|
-
# @return [Source] The Source at a given path.
|
474
|
-
#
|
475
|
-
# @param [Pathname] path
|
476
|
-
# The local file path to one podspec repo.
|
477
|
-
#
|
478
|
-
def source_from_path(path)
|
479
|
-
return Source.new(path) unless path.basename.to_s == 'master'
|
480
|
-
MasterSource.new(path)
|
481
|
-
end
|
482
|
-
|
483
|
-
# @return [Source::Aggregate] The aggregate of the sources from repos.
|
484
|
-
#
|
485
|
-
# @param [Array<Pathname>] repos
|
486
|
-
# The local file paths to one or more podspec repo caches.
|
487
|
-
#
|
488
|
-
def aggregate_with_repos(repos)
|
489
|
-
sources = repos.map { |path| source_from_path(path) }
|
490
|
-
@aggregates_by_repos ||= {}
|
491
|
-
@aggregates_by_repos[repos] ||= Source::Aggregate.new(sources)
|
492
|
-
end
|
493
|
-
|
494
|
-
# @return [Bool] Whether the given path is writable by the current user.
|
495
|
-
#
|
496
|
-
# @param [#to_s] path
|
497
|
-
# The path.
|
498
|
-
#
|
499
|
-
def path_writable?(path)
|
500
|
-
Pathname(path).dirname.writable?
|
501
|
-
end
|
502
|
-
|
503
|
-
# @return [Bool] Whether `gem install` probably needs `sudo` to succeed.
|
504
|
-
#
|
505
|
-
def needs_sudo?
|
506
|
-
!path_writable?(__FILE__)
|
507
|
-
end
|
508
|
-
|
509
|
-
# @return [Source] The git source with the given name. If no git source
|
510
|
-
# with given name is found it raises.
|
511
|
-
#
|
512
|
-
# @param [String] name
|
513
|
-
# The name of the source.
|
514
|
-
#
|
515
|
-
def git_source_named(name)
|
516
|
-
specified_source = aggregate.sources.find { |s| s.name == name }
|
517
|
-
unless specified_source
|
518
|
-
raise Informative, "Unable to find the `#{name}` repo."
|
519
|
-
end
|
520
|
-
unless git_repo?(specified_source.repo)
|
521
|
-
raise Informative, "The `#{name}` repo is not a git repo."
|
522
|
-
end
|
523
|
-
specified_source
|
524
|
-
end
|
525
|
-
|
526
|
-
# @return [Source] The list of the git sources.
|
527
|
-
#
|
528
|
-
def git_sources
|
529
|
-
all.select do |source|
|
530
|
-
git_repo?(source.repo)
|
531
|
-
end
|
532
|
-
end
|
533
|
-
|
534
|
-
# @return [Pathname] The path of the source with the given name.
|
535
|
-
#
|
536
|
-
# @param [String] name
|
537
|
-
# The name of the source.
|
538
|
-
#
|
539
|
-
def source_dir(name)
|
540
|
-
if dir = config.repos_dir + name
|
541
|
-
dir
|
542
|
-
else
|
543
|
-
raise Informative, "Unable to find the `#{name}` repo."
|
544
|
-
end
|
545
|
-
end
|
546
|
-
|
547
|
-
# @return [Source] The source whose {Source#url} is equal to `url`.
|
548
|
-
#
|
549
|
-
# @param [String] url
|
550
|
-
# The URL of the source.
|
551
|
-
#
|
552
|
-
def source_with_url(url)
|
553
|
-
url = url.downcase.gsub(/.git$/, '')
|
554
|
-
aggregate.sources.find do |source|
|
555
|
-
source.url && source.url.downcase.gsub(/.git$/, '') == url
|
556
|
-
end
|
557
|
-
end
|
558
|
-
|
559
|
-
# Returns a suitable repository name for `url`.
|
560
|
-
#
|
561
|
-
# @example A GitHub.com URL
|
562
|
-
#
|
563
|
-
# name_for_url('https://github.com/Artsy/Specs.git')
|
564
|
-
# # "artsy"
|
565
|
-
# name_for_url('https://github.com/Artsy/Specs.git')
|
566
|
-
# # "artsy-1"
|
567
|
-
#
|
568
|
-
# @example A non-Github.com URL
|
569
|
-
#
|
570
|
-
# name_for_url('https://sourceforge.org/Artsy/Specs.git')
|
571
|
-
# # sourceforge-artsy-specs
|
572
|
-
#
|
573
|
-
# @example A file URL
|
574
|
-
#
|
575
|
-
# name_for_url('file:///Artsy/Specs.git')
|
576
|
-
# # artsy-specs
|
577
|
-
#
|
578
|
-
# @param [#to_s] url
|
579
|
-
# The URL of the source.
|
580
|
-
#
|
581
|
-
# @return [String] A suitable repository name for `url`.
|
582
|
-
#
|
583
|
-
def name_for_url(url)
|
584
|
-
base_from_host_and_path = lambda do |host, path|
|
585
|
-
if host
|
586
|
-
base = host.split('.')[-2] || host
|
587
|
-
base += '-'
|
588
|
-
else
|
589
|
-
base = ''
|
590
|
-
end
|
591
|
-
|
592
|
-
base + path.gsub(/.git$/, '').gsub(/^\//, '').split('/').join('-')
|
593
|
-
end
|
594
|
-
|
595
|
-
case url.to_s.downcase
|
596
|
-
when %r{github.com[:/]+cocoapods/specs}
|
597
|
-
base = 'master'
|
598
|
-
when %r{github.com[:/]+(.+)/(.+)}
|
599
|
-
base = Regexp.last_match[1]
|
600
|
-
when /^\S+@(\S+)[:\/]+(.+)$/
|
601
|
-
host, path = Regexp.last_match.captures
|
602
|
-
base = base_from_host_and_path[host, path]
|
603
|
-
when URI.regexp
|
604
|
-
url = URI(url.downcase)
|
605
|
-
base = base_from_host_and_path[url.host, url.path]
|
606
|
-
else
|
607
|
-
base = url.to_s.downcase
|
608
|
-
end
|
609
|
-
|
610
|
-
name = base
|
611
|
-
infinity = 1.0 / 0
|
612
|
-
(1..infinity).each do |i|
|
613
|
-
break unless source_dir(name).exist?
|
614
|
-
name = "#{base}-#{i}"
|
615
|
-
end
|
616
|
-
name
|
617
|
-
end
|
618
95
|
end
|
619
|
-
end
|
620
96
|
|
621
|
-
class Source
|
622
97
|
extend Executable
|
623
98
|
executable :git
|
624
99
|
|
@@ -649,5 +124,33 @@ module Pod
|
|
649
124
|
end
|
650
125
|
super
|
651
126
|
end
|
127
|
+
|
128
|
+
def verify_compatibility!
|
129
|
+
super
|
130
|
+
latest_cocoapods_version = metadata.latest_cocoapods_version && Gem::Version.create(metadata.latest_cocoapods_version)
|
131
|
+
return unless Config.instance.new_version_message? &&
|
132
|
+
latest_cocoapods_version &&
|
133
|
+
latest_cocoapods_version > Gem::Version.new(Pod::VERSION)
|
134
|
+
|
135
|
+
rc = latest_cocoapods_version.prerelease?
|
136
|
+
install_message = !Pathname(__FILE__).dirname.writable? ? 'sudo ' : ''
|
137
|
+
install_message << 'gem install cocoapods'
|
138
|
+
install_message << ' --pre' if rc
|
139
|
+
message = [
|
140
|
+
'',
|
141
|
+
"CocoaPods #{latest_cocoapods_version} is available.".green,
|
142
|
+
"To update use: `#{install_message}`".green,
|
143
|
+
("[!] This is a test version we'd love you to try.".yellow if rc),
|
144
|
+
("Until we reach version 1.0 the features of CocoaPods can and will change.\n" \
|
145
|
+
'We strongly recommend that you use the latest version at all times.'.yellow unless rc),
|
146
|
+
'',
|
147
|
+
'For more information, see https://blog.cocoapods.org ' \
|
148
|
+
'and the CHANGELOG for this version at ' \
|
149
|
+
"https://github.com/CocoaPods/CocoaPods/releases/tag/#{latest_cocoapods_version}".green,
|
150
|
+
'',
|
151
|
+
'',
|
152
|
+
].compact.join("\n")
|
153
|
+
UI.puts(message)
|
154
|
+
end
|
652
155
|
end
|
653
156
|
end
|