cocoapods 1.0.0.beta.6 → 1.0.0.beta.7

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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +46 -0
  3. data/lib/cocoapods.rb +2 -1
  4. data/lib/cocoapods/command.rb +1 -1
  5. data/lib/cocoapods/command/init.rb +4 -4
  6. data/lib/cocoapods/command/install.rb +1 -1
  7. data/lib/cocoapods/command/inter_process_communication.rb +3 -3
  8. data/lib/cocoapods/command/list.rb +1 -1
  9. data/lib/cocoapods/command/outdated.rb +1 -1
  10. data/lib/cocoapods/command/repo/add.rb +1 -1
  11. data/lib/cocoapods/command/repo/lint.rb +6 -6
  12. data/lib/cocoapods/command/repo/list.rb +2 -2
  13. data/lib/cocoapods/command/repo/push.rb +13 -15
  14. data/lib/cocoapods/command/repo/update.rb +1 -1
  15. data/lib/cocoapods/command/setup.rb +2 -2
  16. data/lib/cocoapods/command/spec.rb +1 -1
  17. data/lib/cocoapods/config.rb +5 -0
  18. data/lib/cocoapods/core_overrides.rb +1 -0
  19. data/lib/cocoapods/downloader.rb +5 -18
  20. data/lib/cocoapods/downloader/request.rb +1 -10
  21. data/lib/cocoapods/gem_version.rb +1 -1
  22. data/lib/cocoapods/generator/copy_resources_script.rb +17 -17
  23. data/lib/cocoapods/generator/embed_frameworks_script.rb +2 -2
  24. data/lib/cocoapods/generator/info_plist_file.rb +1 -0
  25. data/lib/cocoapods/installer.rb +3 -1
  26. data/lib/cocoapods/installer/analyzer.rb +4 -4
  27. data/lib/cocoapods/installer/target_installer/pod_target_installer.rb +1 -1
  28. data/lib/cocoapods/resolver.rb +9 -6
  29. data/lib/cocoapods/sandbox/path_list.rb +1 -1
  30. data/lib/cocoapods/sources_manager.rb +42 -539
  31. data/lib/cocoapods/user_interface.rb +4 -0
  32. data/lib/cocoapods/user_interface/error_report.rb +1 -1
  33. data/lib/cocoapods/validator.rb +1 -1
  34. 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
@@ -249,7 +249,9 @@ module Pod
249
249
 
250
250
  remainder = whitelisted_configs - all_user_configurations
251
251
  unless remainder.empty?
252
- raise Informative, "Unknown #{'configuration'.pluralize(remainder.size)} whitelisted: #{remainder.sort.to_sentence}."
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 SourcesManager.git_repo?(source.repo)
220
- SourcesManager.update(source.name)
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 ({SourcesManager.all}).
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
- SourcesManager.find_or_create_source_with_url(source_url)
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 = {
@@ -350,7 +350,7 @@ module Pod
350
350
  #
351
351
  def aggregate_for_dependency(dependency)
352
352
  if dependency && dependency.podspec_repo
353
- return SourcesManager.aggregate_for_dependency(dependency)
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 is no existing specification inside any of the spec repos with given requirements.
424
- message << "\n\nNone of the spec sources contain a spec satisfying the `#{r}` dependency." \
425
- "\nYou have either; mistyped the name or version," \
426
- ' not added the source repo that hosts the Podspec to your Podfile,' \
427
- ' or not got the latest versions of your source repos.'
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
- module Pod
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
- raise Informative, "Unable to add a source with url `#{url}` " \
71
- "named `#{name}`.\nYou can try adding it manually in " \
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
- check_version_information(source.repo)
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