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.
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