cocoapods-core 1.7.5 → 1.8.0.beta.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d40f862cf3a86ca84b6fdfee612e78c9cecc02e97ae8bbc4a099d96088c3f612
4
- data.tar.gz: 2a2e7881179f0f3088d0a9dcebcebfc64f0251923f4d7c6d79013481f4d0ae16
3
+ metadata.gz: b3b9cb102f03fac7ec166a52c1d0b47a4b0bcefec61664061dc1136b96db2d81
4
+ data.tar.gz: a568022e39121dae7ee044b60d58369e543698e6261f5bfc1dafb3469da18512
5
5
  SHA512:
6
- metadata.gz: 3c41e9d914cfda9bf6cbb7d7ae3550d4a0250897180b5a397a1b4da929102aa795fcc28d98df2e765ca3631519c86b721354524f7b70e59c0b6fdfc59d75295f
7
- data.tar.gz: 329736230be1caf67f4eaf0b4965ecfd07031a3dbd1ff3d2692c89311521dafdd4616e5c0369fb7559c9d152ec11896d5e572db3f3cee1fa756453f7cf1f42d9
6
+ metadata.gz: c4f4dad80c9d988f64f83235c53ebc0e532207cda1fb0a7704248d97a4ad733e26831c42f39e2a80fd2a46ceda271ce39fd2c7d76bbff1f0f42a2116ac364473
7
+ data.tar.gz: 73492f7437077ac6f9bfda2edae47a56868b3a3fefb3fc1f37cd6eb739593cd57accb2256a198950ffb3b912f9449807cceb354850c83e1f7c3c137a1db5d4ba
@@ -28,7 +28,7 @@ module Pod
28
28
  autoload :Podfile, 'cocoapods-core/podfile'
29
29
  autoload :Source, 'cocoapods-core/source'
30
30
  autoload :CDNSource, 'cocoapods-core/cdn_source'
31
- autoload :MasterSource, 'cocoapods-core/master_source'
31
+ autoload :TrunkSource, 'cocoapods-core/trunk_source'
32
32
  autoload :Specification, 'cocoapods-core/specification'
33
33
  autoload :StandardError, 'cocoapods-core/standard_error'
34
34
  autoload :YAMLHelper, 'cocoapods-core/yaml_helper'
@@ -6,8 +6,8 @@ module Pod
6
6
  # Subclass of Pod::Source to provide support for CDN-based Specs repositories
7
7
  #
8
8
  class CDNSource < Source
9
- MAX_CDN_NETWORK_THREADS = 50
10
- MAX_NUMBER_OF_RETRIES = 5
9
+ MAX_CDN_NETWORK_THREADS = (ENV['MAX_CDN_NETWORK_THREADS'] || 50).to_i
10
+ MAX_NUMBER_OF_RETRIES = (ENV['COCOAPODS_CDN_MAX_NUMBER_OF_RETRIES'] || 5).to_i
11
11
 
12
12
  # @param [String] repo The name of the repository
13
13
  #
@@ -20,7 +20,7 @@ module Pod
20
20
 
21
21
  @executor = Concurrent::ThreadPoolExecutor.new(
22
22
  :min_threads => 5,
23
- :max_threads => (ENV['MAX_CDN_NETWORK_THREADS'] || MAX_CDN_NETWORK_THREADS).to_i,
23
+ :max_threads => MAX_CDN_NETWORK_THREADS,
24
24
  :max_queue => 0 # unbounded work queue
25
25
  )
26
26
 
@@ -32,7 +32,7 @@ module Pod
32
32
  # @return [String] The URL of the source.
33
33
  #
34
34
  def url
35
- @url ||= File.read(repo.join('.url'))
35
+ @url ||= File.read(repo.join('.url')).chomp.chomp('/') + '/'
36
36
  end
37
37
 
38
38
  # @return [String] The type of the source.
@@ -44,7 +44,8 @@ module Pod
44
44
  def refresh_metadata
45
45
  if metadata.nil?
46
46
  unless repo.exist?
47
- raise Informative, "Unable to find a source named: `#{name}`"
47
+ debug "CDN: Repo #{name} does not exist!"
48
+ return
48
49
  end
49
50
 
50
51
  specs_dir.mkpath
@@ -55,8 +56,9 @@ module Pod
55
56
  end
56
57
 
57
58
  def preheat_existing_files
58
- all_existing_files = [repo.join('**/*.yml'), repo.join('**/*.txt'), repo.join('**/*.json')].map(&Pathname.method(:glob)).flatten
59
- loaders = all_existing_files.map { |f| f.relative_path_from(repo).to_s }.map do |file|
59
+ files_to_update = files_definitely_to_update + deprecated_local_podspecs - ['deprecated_podspecs.txt']
60
+ debug "CDN: #{name} Going to update #{files_to_update.count} files"
61
+ loaders = files_to_update.map do |file|
60
62
  Concurrent::Promises.future_on(@executor) do
61
63
  download_file(file)
62
64
  end
@@ -67,6 +69,17 @@ module Pod
67
69
  end
68
70
  end
69
71
 
72
+ def files_definitely_to_update
73
+ Pathname.glob(repo.join('**/*.{txt,yml}')).map { |f| f.relative_path_from(repo).to_s }
74
+ end
75
+
76
+ def deprecated_local_podspecs
77
+ download_file('deprecated_podspecs.txt')
78
+ local_file('deprecated_podspecs.txt', &:to_a).
79
+ map { |f| Pathname.new(f.chomp) }.
80
+ select { |f| repo.join(f).exist? }
81
+ end
82
+
70
83
  # @return [Pathname] The directory where the specs are stored.
71
84
  #
72
85
  def specs_dir
@@ -143,6 +156,10 @@ module Pod
143
156
  def specification_path(name, version)
144
157
  raise ArgumentError, 'No name' unless name
145
158
  raise ArgumentError, 'No version' unless version
159
+ unless versions(name).include?(Version.new(version))
160
+ raise StandardError, "Unable to find the specification #{name} " \
161
+ "(#{version}) in the #{self.name} source."
162
+ end
146
163
 
147
164
  podspec_version_path_relative = Pathname.new(version.to_s).join("#{name}.podspec.json")
148
165
  relative_podspec = relative_pod_path(name).join(podspec_version_path_relative).to_s
@@ -202,14 +219,21 @@ module Pod
202
219
  # the search term. Can be a regular expression.
203
220
  #
204
221
  # @param [Bool] full_text_search
205
- # not supported due to performance reasons
222
+ # performed using Algolia
206
223
  #
207
224
  # @note full text search requires to load the specification for each pod,
208
225
  # and therefore not supported.
209
226
  #
210
227
  def search_by_name(query, full_text_search = false)
211
228
  if full_text_search
212
- raise Informative, "Can't perform full text search, it will take forever"
229
+ require 'algoliasearch'
230
+ begin
231
+ algolia_result = algolia_search_index.search(query, :attributesToRetrieve => 'name')
232
+ names = algolia_result['hits'].map { |r| r['name'] }
233
+ names.map { |n| set(n) }.reject { |s| s.versions.compact.empty? }
234
+ rescue Algolia::AlgoliaError => e
235
+ raise Informative, "CDN: #{name} - Cannot perform full-text search because Algolia returned an error: #{e}"
236
+ end
213
237
  else
214
238
  super(query)
215
239
  end
@@ -233,14 +257,18 @@ module Pod
233
257
  []
234
258
  end
235
259
 
236
- def git?
237
- # Long story here. This property is actually used solely by Source::Manager to determine
238
- # which sources are updatable. Ideally, this would require a name change but @segiddins
239
- # has pointed out that it is public and could break plugins.
240
- # In any case, CDN-backed repos can be updated and therefore the value ought to be true.
260
+ def updateable?
241
261
  true
242
262
  end
243
263
 
264
+ def git?
265
+ false
266
+ end
267
+
268
+ def indexable?
269
+ false
270
+ end
271
+
244
272
  private
245
273
 
246
274
  def ensure_versions_file_loaded(fragment)
@@ -261,6 +289,18 @@ module Pod
261
289
  end
262
290
  end
263
291
 
292
+ def algolia_search_index
293
+ @index ||= begin
294
+ require 'algoliasearch'
295
+
296
+ raise Informative, "Cannot perform full-text search in repo #{name} because it's missing Algolia config" if download_file('AlgoliaSearch.yml').nil?
297
+ algolia_config = YAMLHelper.load_string(local_file('AlgoliaSearch.yml', &:read))
298
+
299
+ client = Algolia::Client.new(:application_id => algolia_config['application_id'], :api_key => algolia_config['api_key'])
300
+ Algolia::Index.new(algolia_config['index'], client)
301
+ end
302
+ end
303
+
264
304
  def index_file_name_for_fragment(fragment)
265
305
  fragment_joined = fragment.join('_')
266
306
  fragment_joined = '_' + fragment_joined unless fragment.empty?
@@ -305,18 +345,20 @@ module Pod
305
345
  etag = File.read(etag_path) if File.exist?(etag_path)
306
346
  debug "CDN: #{name} Relative path: #{partial_url}, has ETag? #{etag}" unless etag.nil?
307
347
 
308
- download_from_url(partial_url, file_remote_url, etag)
348
+ download_retrying_retryable_errors(partial_url, file_remote_url, etag)
309
349
  end
310
350
 
311
- def download_from_url(partial_url, file_remote_url, etag)
351
+ def download_retrying_retryable_errors(partial_url, file_remote_url, etag, retries = MAX_NUMBER_OF_RETRIES)
312
352
  path = repo + partial_url
313
353
  etag_path = path.sub_ext(path.extname + '.etag')
314
354
 
315
- response = download_retrying_connection_errors(partial_url, file_remote_url, etag)
355
+ response = download_retrying_connection_errors(partial_url, file_remote_url, etag, retries)
316
356
 
317
357
  case response.status_code
318
358
  when 301
319
- download_from_url(partial_url, response.headers['location'].first, etag)
359
+ redirect_location = response.headers['location'].first
360
+ debug "CDN: #{name} Redirecting from #{file_remote_url} to #{redirect_location}"
361
+ download_retrying_retryable_errors(partial_url, redirect_location, etag)
320
362
  when 304
321
363
  debug "CDN: #{name} Relative path not modified: #{partial_url}"
322
364
  # We need to update the file modification date, as it is later used for freshness
@@ -333,16 +375,32 @@ module Pod
333
375
  when 404
334
376
  debug "CDN: #{name} Relative path couldn't be downloaded: #{partial_url} Response: #{response.status_code}"
335
377
  nil
378
+ when 502, 503, 504
379
+ if retries <= 1
380
+ raise Informative, "CDN: #{name} URL couldn't be downloaded: #{file_remote_url} Response: #{response.status_code}"
381
+ else
382
+ sleep_for(backoff_time(retries))
383
+ download_retrying_retryable_errors(partial_url, file_remote_url, etag, retries - 1)
384
+ end
336
385
  else
337
- raise Informative, "CDN: #{name} Relative path couldn't be downloaded: #{partial_url} Response: #{response.status_code}"
386
+ raise Informative, "CDN: #{name} URL couldn't be downloaded: #{file_remote_url} Response: #{response.status_code}"
338
387
  end
339
388
  end
340
389
 
341
- def download_retrying_connection_errors(partial_url, file_remote_url, etag, retries = MAX_NUMBER_OF_RETRIES)
390
+ def backoff_time(retries)
391
+ current_retry = MAX_NUMBER_OF_RETRIES - retries
392
+ 4 * 2**current_retry
393
+ end
394
+
395
+ def sleep_for(seconds)
396
+ sleep(seconds)
397
+ end
398
+
399
+ def download_retrying_connection_errors(partial_url, file_remote_url, etag, retries)
342
400
  etag.nil? ? REST.get(file_remote_url) : REST.get(file_remote_url, 'If-None-Match' => etag)
343
401
  rescue REST::Error => e
344
- if retries <= 0
345
- raise Informative, "CDN: #{name} Relative path couldn't be downloaded: #{partial_url}, error: #{e}"
402
+ if retries <= 1
403
+ raise Informative, "CDN: #{name} URL couldn't be downloaded: #{file_remote_url}, error: #{e}"
346
404
  else
347
405
  debug "CDN: #{name} Relative path: #{partial_url} error: #{e} - retrying"
348
406
  download_retrying_connection_errors(partial_url, file_remote_url, etag, retries - 1)
@@ -69,20 +69,6 @@ module Pod
69
69
  #
70
70
  # Dependency.new('Artsy+UILabels', '~> 1.0', :source => 'https://github.com/Artsy/Specs.git')
71
71
  #
72
- # @overload initialize(name, is_head)
73
- #
74
- # @param [String] name
75
- # the name of the Pod.
76
- #
77
- # @param [Symbol] is_head
78
- # a symbol that can be `:head` or nil.
79
- #
80
- # @todo Remove `:head` code once everyone has migrated past CocoaPods 1.0.
81
- #
82
- # @example Initialization with the head option
83
- #
84
- # Dependency.new('RestKit', :head)
85
- #
86
72
  def initialize(name = nil, *requirements)
87
73
  if requirements.last.is_a?(Hash)
88
74
  additional_params = requirements.pop.select { |_, v| !v.nil? }
@@ -122,10 +108,6 @@ module Pod
122
108
  # @return [Requirement] the requirement of this dependency (a set of
123
109
  # one or more version restrictions).
124
110
  #
125
- # @todo The specific version is stripped from head information because
126
- # because its string representation would not parse. It would
127
- # be better to add something like Version#display_string.
128
- #
129
111
  def requirement
130
112
  if specific_version
131
113
  Requirement.new(Version.new(specific_version.version))
@@ -291,8 +273,8 @@ module Pod
291
273
  # @return [Bool] Whether the dependency has any pre-release requirements
292
274
  #
293
275
  def prerelease?
294
- @prerelease ||= requirement.requirements.
295
- any? { |r| Version.new(r[1].version).prerelease? }
276
+ return @prerelease if defined?(@prerelease)
277
+ @prerelease = requirement.requirements.any? { |_op, version| version.prerelease? }
296
278
  end
297
279
 
298
280
  # Checks whether the dependency would be satisfied by the specification
@@ -357,8 +339,6 @@ module Pod
357
339
  # part by clients that need to create a dependency equal to the
358
340
  # original one.
359
341
  #
360
- # @todo Remove the `HEAD` code once everyone has migrated past 1.0.
361
- #
362
342
  # @return [Dependency] the dependency described by the string.
363
343
  #
364
344
  def self.from_string(string)
@@ -367,9 +347,6 @@ module Pod
367
347
  version = match_data[2]
368
348
  version = version.gsub(/[()]/, '') if version
369
349
  case version
370
- when / HEAD( \(based on #{Pod::Version::VERSION_PATTERN}\))?/
371
- CoreUI.warn "Ignoring obsolete `HEAD` specifier in `#{string}`"
372
- Dependency.new(name)
373
350
  when nil, /from `(.*)(`|')/
374
351
  Dependency.new(name)
375
352
  else
@@ -1,5 +1,5 @@
1
1
  module Pod
2
2
  # The version of the cocoapods-core.
3
3
  #
4
- CORE_VERSION = '1.7.5'.freeze unless defined? Pod::CORE_VERSION
4
+ CORE_VERSION = '1.8.0.beta.1'.freeze unless defined? Pod::CORE_VERSION
5
5
  end
@@ -8,11 +8,11 @@ module Pod
8
8
  #
9
9
  # @return [string]
10
10
  #
11
- def self.get_actual_url(url)
11
+ def self.get_actual_url(url, user_agent = nil)
12
12
  redirects = 0
13
13
 
14
14
  loop do
15
- response = perform_head_request(url)
15
+ response = perform_head_request(url, user_agent)
16
16
 
17
17
  if [301, 302, 303, 307, 308].include? response.status_code
18
18
  location = response.headers['location'].first
@@ -38,12 +38,12 @@ module Pod
38
38
  #
39
39
  # @return [REST::response]
40
40
  #
41
- def self.validate_url(url)
41
+ def self.validate_url(url, user_agent = nil)
42
42
  return nil unless url =~ /^#{URI.regexp}$/
43
43
 
44
44
  begin
45
- url = get_actual_url(url)
46
- resp = perform_head_request(url)
45
+ url = get_actual_url(url, user_agent)
46
+ resp = perform_head_request(url, user_agent)
47
47
  rescue SocketError, URI::InvalidURIError, REST::Error, REST::Error::Connection
48
48
  resp = nil
49
49
  end
@@ -59,17 +59,19 @@ module Pod
59
59
  #
60
60
  # @return [REST::response]
61
61
  #
62
- def self.perform_head_request(url)
62
+ def self.perform_head_request(url, user_agent)
63
63
  require 'rest'
64
64
 
65
- resp = ::REST.head(url, 'User-Agent' => USER_AGENT)
65
+ user_agent ||= USER_AGENT
66
+
67
+ resp = ::REST.head(url, 'User-Agent' => user_agent)
66
68
 
67
69
  if resp.status_code >= 400
68
- resp = ::REST.get(url, 'User-Agent' => USER_AGENT,
70
+ resp = ::REST.get(url, 'User-Agent' => user_agent,
69
71
  'Range' => 'bytes=0-0')
70
72
 
71
73
  if resp.status_code >= 400
72
- resp = ::REST.get(url, 'User-Agent' => USER_AGENT)
74
+ resp = ::REST.get(url, 'User-Agent' => user_agent)
73
75
  end
74
76
  end
75
77
 
@@ -489,7 +489,7 @@ module Pod
489
489
  next unless source
490
490
  next if specs.empty?
491
491
  key = source.url || source.name
492
- key = key.downcase if source.name == Pod::MasterSource::MASTER_REPO_NAME
492
+ key = Pod::TrunkSource::TRUNK_REPO_NAME if source.name == Pod::TrunkSource::TRUNK_REPO_NAME
493
493
  value = specs.map { |s| s.root.name }.uniq
494
494
  [key, YAMLHelper.sorted_array(value)]
495
495
  end.compact]
@@ -687,6 +687,39 @@ module Pod
687
687
  current_target_definition.use_frameworks!(flag)
688
688
  end
689
689
 
690
+ # Specifies the Swift version requirements this target definition supports.
691
+ #
692
+ # **Note** These requirements are inherited from the parent, if specified and if none
693
+ # are specified at the root level then all versions are considered to be supported.
694
+ #
695
+ # @param [String, Version, Array<String>, Array<Version>] requirements
696
+ # The set of requirements this target supports.
697
+ #
698
+ # @example
699
+ #
700
+ # target 'MyApp' do
701
+ # supports_swift_versions '>= 3.0', '< 4.0'
702
+ # pod 'AFNetworking', '~> 1.0'
703
+ # end
704
+ #
705
+ # @example
706
+ #
707
+ # supports_swift_versions '>= 3.0', '< 4.0'
708
+ #
709
+ # target 'MyApp' do
710
+ # pod 'AFNetworking', '~> 1.0'
711
+ # end
712
+ #
713
+ # target 'ZipApp' do
714
+ # pod 'SSZipArchive'
715
+ # end
716
+ #
717
+ # @return [void]
718
+ #
719
+ def supports_swift_versions(*requirements)
720
+ current_target_definition.store_swift_version_requirements(*requirements)
721
+ end
722
+
690
723
  #-----------------------------------------------------------------------#
691
724
 
692
725
  # @!group Workspace
@@ -869,39 +902,6 @@ module Pod
869
902
  raise Informative, 'Specifying multiple `post_install` hooks is unsupported.' if @post_install_callback
870
903
  @post_install_callback = block
871
904
  end
872
-
873
- # Specifies the Swift version requirements this target definition supports.
874
- #
875
- # **Note** These requirements are inherited from the parent, if specified and if none
876
- # are specified at the root level then all versions are considered to be supported.
877
- #
878
- # @param [String, Version, Array<String>, Array<Version>] requirements
879
- # The set of requirements this target supports.
880
- #
881
- # @example
882
- #
883
- # target 'MyApp' do
884
- # supports_swift_versions '>= 3.0', '< 4.0'
885
- # pod 'AFNetworking', '~> 1.0'
886
- # end
887
- #
888
- # @example
889
- #
890
- # supports_swift_versions '>= 3.0', '< 4.0'
891
- #
892
- # target 'MyApp' do
893
- # pod 'AFNetworking', '~> 1.0'
894
- # end
895
- #
896
- # target 'ZipApp' do
897
- # pod 'SSZipArchive'
898
- # end
899
- #
900
- # @return [void]
901
- #
902
- def supports_swift_versions(*requirements)
903
- current_target_definition.store_swift_version_requirements(*requirements)
904
- end
905
905
  end
906
906
  end
907
907
  end
@@ -296,6 +296,20 @@ module Pod
296
296
 
297
297
  #--------------------------------------#
298
298
 
299
+ # @return [String] The project name to use for the given pod name or `nil` if none specified.
300
+ #
301
+ # @note When querying for a subspec then use the root pod spec name instead as this is what's stored.
302
+ #
303
+ def project_name_for_pod(pod_name)
304
+ if root?
305
+ raw_project_names_hash[pod_name]
306
+ else
307
+ raw_project_names_hash[pod_name] || parent.project_name_for_pod(pod_name)
308
+ end
309
+ end
310
+
311
+ #--------------------------------------#
312
+ #
299
313
  # @return [Bool] whether the target definition should inhibit warnings
300
314
  # for a single pod. If inhibit_all_warnings is true, it will
301
315
  # return true for any asked pod.
@@ -666,6 +680,7 @@ module Pod
666
680
  parse_inhibit_warnings(name, requirements)
667
681
  parse_modular_headers(name, requirements)
668
682
  parse_configuration_whitelist(name, requirements)
683
+ parse_project_name(name, requirements)
669
684
 
670
685
  if requirements && !requirements.empty?
671
686
  pod = { name => requirements }
@@ -769,6 +784,7 @@ module Pod
769
784
  use_modular_headers
770
785
  user_project_path
771
786
  build_configurations
787
+ project_names
772
788
  dependencies
773
789
  script_phases
774
790
  children
@@ -1041,6 +1057,33 @@ module Pod
1041
1057
  requirements.pop if options.empty?
1042
1058
  end
1043
1059
 
1060
+ # Removes :project_name from the requirements list, and adds
1061
+ # the pods name into internal hash.
1062
+ #
1063
+ # @param [String] name The name of the pod
1064
+ #
1065
+ # @param [Array] requirements
1066
+ # If :project_name is the only key in the hash, the hash
1067
+ # should be destroyed because it confuses Gem::Dependency.
1068
+ #
1069
+ # @return [void]
1070
+ #
1071
+ def parse_project_name(name, requirements)
1072
+ options = requirements.last
1073
+ return requirements unless options.is_a?(Hash)
1074
+
1075
+ project_name = options.delete(:project_name)
1076
+ pod_name = Specification.root_name(name)
1077
+ raw_project_names_hash[pod_name] = project_name if project_name
1078
+
1079
+ requirements.pop if options.empty?
1080
+ end
1081
+
1082
+ def raw_project_names_hash
1083
+ get_hash_value('project_names', {})
1084
+ end
1085
+ private :raw_project_names_hash
1086
+
1044
1087
  # Removes :configurations or :configuration from the requirements list,
1045
1088
  # and adds the pod's name into the internal hash for which pods should be
1046
1089
  # linked in which configuration only.
@@ -16,6 +16,9 @@ module Pod
16
16
  # "#{SPEC_NAME}/#{VERSION}/#{SPEC_NAME}.podspec"
17
17
  #
18
18
  class Source
19
+ # The default branch in which the specs are stored
20
+ DEFAULT_SPECS_BRANCH = 'master'.freeze
21
+
19
22
  # @return [Pod::Source::Metadata] The metadata for this source.
20
23
  #
21
24
  attr_reader :metadata
@@ -55,7 +58,7 @@ module Pod
55
58
  # @return [String] The type of the source.
56
59
  #
57
60
  def type
58
- 'file system'
61
+ git? ? 'git' : 'file system'
59
62
  end
60
63
 
61
64
  alias_method :to_s, :name
@@ -353,8 +356,16 @@ module Pod
353
356
  diff_until_commit_hash(prev_commit_hash)
354
357
  end
355
358
 
359
+ def updateable?
360
+ git?
361
+ end
362
+
356
363
  def git?
357
- !repo_git(%w(rev-parse HEAD)).empty?
364
+ repo.join('.git').exist? && !repo_git(%w(rev-parse HEAD)).empty?
365
+ end
366
+
367
+ def indexable?
368
+ true
358
369
  end
359
370
 
360
371
  def verify_compatibility!
@@ -435,7 +446,7 @@ module Pod
435
446
 
436
447
  def git_tracking_branch
437
448
  path = repo.join('.git', 'cocoapods_branch')
438
- path.file? ? path.read.strip : Pod::MasterSource::MASTER_REPO_NAME
449
+ path.file? ? path.read.strip : DEFAULT_SPECS_BRANCH
439
450
  end
440
451
 
441
452
  def diff_until_commit_hash(commit_hash)
@@ -58,10 +58,17 @@ module Pod
58
58
  aggregate.sources
59
59
  end
60
60
 
61
+ # @return [Array<Source>] The list of all the non-indexable sources known to this
62
+ # installation of CocoaPods.
63
+ #
64
+ def all_non_indexable
65
+ aggregate.sources.reject(&:indexable?)
66
+ end
67
+
61
68
  # @return [Array<Source>] The CocoaPods Master Repo source.
62
69
  #
63
70
  def master
64
- sources([Pod::MasterSource::MASTER_REPO_NAME]).select { |s| s.repo.directory? }
71
+ sources([Pod::TrunkSource::TRUNK_REPO_NAME]).select { |s| s.repo.directory? }
65
72
  end
66
73
 
67
74
  # @!group Master repo
@@ -69,7 +76,7 @@ module Pod
69
76
  # @return [Pathname] The path of the master repo.
70
77
  #
71
78
  def master_repo_dir
72
- source_dir(Pod::MasterSource::MASTER_REPO_NAME)
79
+ source_dir(Pod::TrunkSource::TRUNK_REPO_NAME)
73
80
  end
74
81
 
75
82
  # @return [Bool] Checks if the master repo is usable.
@@ -122,9 +129,15 @@ module Pod
122
129
  end
123
130
  found_set_names = query_word_results_hash.values.reduce(:&)
124
131
  found_set_names ||= []
132
+
133
+ sets_from_non_indexable = all_non_indexable.map { |s| s.search_by_name(query, true) }.flatten
134
+
135
+ found_set_names += sets_from_non_indexable.map(&:name).flatten.uniq
136
+
125
137
  sets = found_set_names.map do |name|
126
138
  aggregate.representative_set(name)
127
139
  end
140
+
128
141
  # Remove nil values because representative_set return nil if no pod is found in any of the sources.
129
142
  sets.compact!
130
143
  else
@@ -182,7 +195,7 @@ module Pod
182
195
  #
183
196
  def updated_search_index
184
197
  index = stored_search_index || {}
185
- all.each do |source|
198
+ indexable_sources.each do |source|
186
199
  source_name = source.name
187
200
  unless index[source_name]
188
201
  CoreUI.print "Creating search index for spec repo '#{source_name}'.."
@@ -203,6 +216,7 @@ module Pod
203
216
  search_index = stored_search_index
204
217
  return unless search_index
205
218
  changed_spec_paths.each_pair do |source, spec_paths|
219
+ next unless source.indexable?
206
220
  index_for_source = search_index[source.name]
207
221
  next unless index_for_source && !spec_paths.empty?
208
222
  updated_pods = source.pods_for_specification_paths(spec_paths)
@@ -290,10 +304,10 @@ module Pod
290
304
  def source_from_path(path)
291
305
  @sources_by_path ||= Hash.new do |hash, key|
292
306
  hash[key] = case
307
+ when key.basename.to_s == Pod::TrunkSource::TRUNK_REPO_NAME
308
+ TrunkSource.new(key)
293
309
  when (key + '.url').exist?
294
310
  CDNSource.new(key)
295
- when key.basename.to_s == Pod::MasterSource::MASTER_REPO_NAME
296
- MasterSource.new(key)
297
311
  else
298
312
  Source.new(key)
299
313
  end
@@ -312,27 +326,33 @@ module Pod
312
326
  @aggregates_by_repos[repos] ||= Source::Aggregate.new(sources)
313
327
  end
314
328
 
315
- # @return [Source] The git source with the given name. If no git source
329
+ # @return [Source] The updateable source with the given name. If no updateable source
316
330
  # with given name is found it raises.
317
331
  #
318
332
  # @param [String] name
319
333
  # The name of the source.
320
334
  #
321
- def git_source_named(name)
335
+ def updateable_source_named(name)
322
336
  specified_source = sources([name]).first
323
337
  unless specified_source
324
338
  raise Informative, "Unable to find the `#{name}` repo."
325
339
  end
326
- unless specified_source.git?
327
- raise Informative, "The `#{name}` repo is not a git repo."
340
+ unless specified_source.updateable?
341
+ raise Informative, "The `#{name}` repo is not a updateable repo."
328
342
  end
329
343
  specified_source
330
344
  end
331
345
 
332
- # @return [Source] The list of the git sources.
346
+ # @return [Source] The list of the updateable sources.
333
347
  #
334
- def git_sources
335
- all.select(&:git?)
348
+ def updateable_sources
349
+ all.select(&:updateable?)
350
+ end
351
+
352
+ # @return [Source] The list of the indexable sources.
353
+ #
354
+ def indexable_sources
355
+ all.select(&:indexable?)
336
356
  end
337
357
 
338
358
  # @return [Pathname] The path of the source with the given name.
@@ -350,13 +370,17 @@ module Pod
350
370
  # The URL of the source.
351
371
  #
352
372
  def source_with_url(url)
353
- url = url.downcase.gsub(/.git$/, '')
373
+ url = canonic_url(url)
354
374
  url = 'https://github.com/cocoapods/specs' if url =~ %r{github.com[:/]+cocoapods/specs}
355
375
  all.find do |source|
356
- source.url && source.url.downcase.gsub(/.git$/, '') == url
376
+ source.url && canonic_url(source.url) == url
357
377
  end
358
378
  end
359
379
 
380
+ def canonic_url(url)
381
+ url.downcase.gsub(/\.git$/, '').gsub(%r{\/$}, '')
382
+ end
383
+
360
384
  # Returns a suitable repository name for `url`.
361
385
  #
362
386
  # @example A GitHub.com URL
@@ -394,8 +418,8 @@ module Pod
394
418
  end
395
419
 
396
420
  case url.to_s.downcase
397
- when %r{github.com[:/]+cocoapods/specs}
398
- base = Pod::MasterSource::MASTER_REPO_NAME
421
+ when %r{https://#{Regexp.quote(trunk_repo_hostname)}}i
422
+ base = Pod::TrunkSource::TRUNK_REPO_NAME
399
423
  when %r{github.com[:/]+(.+)/(.+)}
400
424
  base = Regexp.last_match[1]
401
425
  when %r{^\S+@(\S+)[:/]+(.+)$}
@@ -416,6 +440,12 @@ module Pod
416
440
  end
417
441
  name
418
442
  end
443
+
444
+ # Returns hostname for for `trunk` URL.
445
+ #
446
+ def trunk_repo_hostname
447
+ URI.parse(TrunkSource::TRUNK_REPO_URL).host.downcase.freeze
448
+ end
419
449
  end
420
450
  end
421
451
  end
@@ -125,8 +125,9 @@ module Pod
125
125
  # clients.
126
126
  #
127
127
  def to_s
128
- if name && !version.version.empty?
129
- "#{name} (#{version})"
128
+ specified_version = raw_version || ''
129
+ if name && !specified_version.empty?
130
+ "#{name} (#{specified_version})"
130
131
  elsif name
131
132
  name
132
133
  else
@@ -203,6 +204,13 @@ module Pod
203
204
  gsub(/[^a-zA-Z0-9_]/, '_').gsub(/_+/, '_')
204
205
  end
205
206
 
207
+ # @return [Object, Nil]
208
+ # the raw value specified for the version attribute, or nil
209
+ #
210
+ def raw_version
211
+ root.attributes_hash['version']
212
+ end
213
+
206
214
  #-------------------------------------------------------------------------#
207
215
 
208
216
  public
@@ -435,6 +443,12 @@ module Pod
435
443
  Specification.convert_keys_to_symbol(value, :recursive => false)
436
444
  end
437
445
 
446
+ # @return [Hash] The Info.plist value.
447
+ #
448
+ def info_plist
449
+ attributes_hash['info_plist'] || {}
450
+ end
451
+
438
452
  #-------------------------------------------------------------------------#
439
453
 
440
454
  public
@@ -689,18 +703,18 @@ module Pod
689
703
  def self.from_string(spec_contents, path, subspec_name = nil)
690
704
  path = Pathname.new(path).expand_path
691
705
  spec = nil
692
- Dir.chdir(path.parent.directory? ? path.parent : Dir.pwd) do
693
- case path.extname
694
- when '.podspec'
706
+ case path.extname
707
+ when '.podspec'
708
+ Dir.chdir(path.parent.directory? ? path.parent : Dir.pwd) do
695
709
  spec = ::Pod._eval_podspec(spec_contents, path)
696
710
  unless spec.is_a?(Specification)
697
711
  raise Informative, "Invalid podspec file at path `#{path}`."
698
712
  end
699
- when '.json'
700
- spec = Specification.from_json(spec_contents)
701
- else
702
- raise Informative, "Unsupported specification format `#{path.extname}` for spec at `#{path}`."
703
713
  end
714
+ when '.json'
715
+ spec = Specification.from_json(spec_contents)
716
+ else
717
+ raise Informative, "Unsupported specification format `#{path.extname}` for spec at `#{path}`."
704
718
  end
705
719
 
706
720
  spec.defined_in_file = path
@@ -110,6 +110,10 @@ module Pod
110
110
  merge_values(attr, value_for_attribute(:xcconfig), value_for_attribute(:user_target_xcconfig))
111
111
  end
112
112
 
113
+ # @return [Hash{String => String}] the Info.plist values for the current specification
114
+ #
115
+ spec_attr_accessor :info_plist
116
+
113
117
  # @return [String] The contents of the prefix header.
114
118
  #
115
119
  spec_attr_accessor :prefix_header_contents
@@ -144,6 +148,10 @@ module Pod
144
148
  spec_attr_accessor :requires_app_host
145
149
  alias_method :requires_app_host?, :requires_app_host
146
150
 
151
+ # @return [String] Name of the app host this spec requires
152
+ #
153
+ spec_attr_accessor :app_host_name
154
+
147
155
  # @return [Symbol] the test type supported by this specification.
148
156
  #
149
157
  spec_attr_accessor :test_type
@@ -309,12 +317,7 @@ module Pod
309
317
  r.compact
310
318
  elsif attr.container == Hash
311
319
  existing_value.merge(new_value) do |_, old, new|
312
- if new.is_a?(Array) || old.is_a?(Array)
313
- r = [*old] + [*new]
314
- r.compact
315
- else
316
- old + ' ' + new
317
- end
320
+ merge_hash_value(attr, old, new)
318
321
  end
319
322
  else
320
323
  new_value
@@ -349,6 +352,35 @@ module Pod
349
352
  end
350
353
  end
351
354
 
355
+ private
356
+
357
+ # Merges two values in a hash together based on the needs of the attribute
358
+ #
359
+ # @param [Specification::DSL::Attribute] attr
360
+ # the attribute for which that value is needed.
361
+ #
362
+ # @param [Object] old the value from the original hash
363
+ #
364
+ # @param [Object] new the value from the new hash
365
+ #
366
+ # @return [Object] the merged value
367
+ #
368
+ def merge_hash_value(attr, old, new)
369
+ case attr.name
370
+ when :info_plist
371
+ new
372
+ when ->(name) { spec.non_library_specification? && [:pod_target_xcconfig, :user_target_xcconfig, :xcconfig].include?(name) }
373
+ new
374
+ else
375
+ if new.is_a?(Array) || old.is_a?(Array)
376
+ r = Array(old) + Array(new)
377
+ r.compact
378
+ else
379
+ old + ' ' + new
380
+ end
381
+ end
382
+ end
383
+
352
384
  # @!group Preparing Values
353
385
  #-----------------------------------------------------------------------#
354
386
 
@@ -305,7 +305,7 @@ module Pod
305
305
  :git => [:tag, :branch, :commit, :submodules].freeze,
306
306
  :svn => [:folder, :tag, :revision].freeze,
307
307
  :hg => [:revision].freeze,
308
- :http => [:flatten, :type, :sha256, :sha1].freeze,
308
+ :http => [:flatten, :type, :sha256, :sha1, :headers].freeze,
309
309
  }.freeze
310
310
 
311
311
  # @!method source=(source)
@@ -704,6 +704,39 @@ module Pod
704
704
 
705
705
  #------------------#
706
706
 
707
+ # @!method info_plist=(info_plist)
708
+ #
709
+ # Key-Value pairs to add to the generated `Info.plist`.
710
+ #
711
+ # The values will be merged with the default values that
712
+ # CocoaPods generates, overriding any duplicates.
713
+ #
714
+ # For library specs, the values will be merged into the generated Info.plist
715
+ # for libraries that are integrated using frameworks. It will have no effect
716
+ # for static libraries.
717
+ #
718
+ # Subspecs (other than app and test specs) are not supported.
719
+ #
720
+ # For app specs, the values will be merged into the application host's `Info.plist`.
721
+ #
722
+ # For test specs, the values will be merged into the test bundle's `Info.plist`.
723
+ #
724
+ # @example
725
+ #
726
+ # spec.info_plist = {
727
+ # 'CFBundleIdentifier' => 'com.myorg.MyLib',
728
+ # 'MY_VAR' => 'SOME_VALUE'
729
+ # }
730
+ #
731
+ # @param [Hash] info_plist
732
+ # The Info.plist values for the Pod.
733
+ #
734
+ attribute :info_plist,
735
+ :container => Hash,
736
+ :inherited => false
737
+
738
+ #------------------#
739
+
707
740
  # @!method requires_arc=(flag)
708
741
  #
709
742
  # `requires_arc` allows you to specify which source_files use ARC.
@@ -1155,7 +1188,8 @@ module Pod
1155
1188
  #
1156
1189
  # ---
1157
1190
  #
1158
- # These are the headers that will be exposed to the user’s project and
1191
+ # These patterns are matched against the source files to include headers
1192
+ # that will be exposed to the user’s project and
1159
1193
  # from which documentation will be generated. When the library is built,
1160
1194
  # these headers will appear in the build directory. If no public headers
1161
1195
  # are specified then **all** the headers in source_files are considered
@@ -1470,7 +1504,7 @@ module Pod
1470
1504
 
1471
1505
  # The list of the test types currently supported.
1472
1506
  #
1473
- SUPPORTED_TEST_TYPES = [:unit].freeze
1507
+ SUPPORTED_TEST_TYPES = [:unit, :ui].freeze
1474
1508
 
1475
1509
  # The test type this specification supports. This only applies to test specifications.
1476
1510
  #
@@ -1508,6 +1542,39 @@ module Pod
1508
1542
  :default_value => false,
1509
1543
  :spec_types => [:test]
1510
1544
 
1545
+ # @!method app_host_name=(name)
1546
+ #
1547
+ # The app specification to use as an app host, if necessary.
1548
+ #
1549
+ # @note
1550
+ #
1551
+ # You must depend on that app spec using `test_spec.dependency 'PodName'`.
1552
+ #
1553
+ # @example
1554
+ #
1555
+ # Pod::Spec.new do |spec|
1556
+ # spec.name = 'NSAttributedString+CCLFormat'
1557
+ #
1558
+ # spec.test_spec do |test_spec|
1559
+ # test_spec.source_files = 'NSAttributedString+CCLFormatTests.m'
1560
+ # test_spec.requires_app_host = true
1561
+ # test_spec.app_host_name = 'NSAttributedString+CCLFormat/App'
1562
+ # test_spec.dependency 'NSAttributedString+CCLFormat/App'
1563
+ # end
1564
+ #
1565
+ # spec.app_spec 'App' do |app_spec|
1566
+ # app_spec.source_files = 'NSAttributedString+CCLFormat.m'
1567
+ # app_spec.dependency 'AFNetworking'
1568
+ # end
1569
+ # end
1570
+ #
1571
+ # @param [String] name
1572
+ # The app specification to use as an app host, if necessary.
1573
+ #
1574
+ attribute :app_host_name,
1575
+ :types => [String],
1576
+ :spec_types => [:test]
1577
+
1511
1578
  SCHEME_KEYS = [:launch_arguments, :environment_variables].freeze
1512
1579
 
1513
1580
  # @!method scheme=(flag)
@@ -121,15 +121,19 @@ module Pod
121
121
  def check_required_attributes
122
122
  attributes = DSL.attributes.values.select(&:required?)
123
123
  attributes.each do |attr|
124
- value = spec.send(attr.name)
125
- unless value && (!value.respond_to?(:empty?) || !value.empty?)
126
- if attr.name == :license
127
- results.add_warning('attributes', 'Missing required attribute ' \
128
- "`#{attr.name}`.")
129
- else
130
- results.add_error('attributes', 'Missing required attribute ' \
131
- "`#{attr.name}`.")
124
+ begin
125
+ value = spec.send(attr.name)
126
+ unless value && (!value.respond_to?(:empty?) || !value.empty?)
127
+ if attr.name == :license
128
+ results.add_warning('attributes', 'Missing required attribute ' \
129
+ "`#{attr.name}`.")
130
+ else
131
+ results.add_error('attributes', 'Missing required attribute ' \
132
+ "`#{attr.name}`.")
133
+ end
132
134
  end
135
+ rescue => exception
136
+ results.add_error('attributes', "Unable to parse attribute `#{attr.name}` due to error: #{exception}")
133
137
  end
134
138
  end
135
139
  end
@@ -187,9 +191,13 @@ module Pod
187
191
  attributes.each do |attr|
188
192
  validation_hook = "_validate_#{attr.name}"
189
193
  next unless respond_to?(validation_hook, true)
190
- value = target.send(attr.name)
191
- next unless value
192
- send(validation_hook, value)
194
+ begin
195
+ value = target.send(attr.name)
196
+ next unless value
197
+ send(validation_hook, value)
198
+ rescue => e
199
+ results.add_error(attr.name, "Unable to validate due to exception: #{e}")
200
+ end
193
201
  end
194
202
  end
195
203
 
@@ -350,6 +358,7 @@ module Pod
350
358
  # Performs validations related to the `source` attribute.
351
359
  #
352
360
  def _validate_source(s)
361
+ return unless s.is_a?(Hash)
353
362
  if git = s[:git]
354
363
  tag, commit = s.values_at(:tag, :commit)
355
364
  version = spec.version.to_s
@@ -394,6 +403,18 @@ module Pod
394
403
  end
395
404
  end
396
405
 
406
+ def _validate_app_host_name(n)
407
+ unless consumer.requires_app_host?
408
+ results.add_error('app_host_name', '`requires_app_host` must be set to ' \
409
+ '`true` when `app_host_name` is specified.')
410
+ end
411
+
412
+ unless consumer.dependencies.map(&:name).include?(n)
413
+ results.add_error('app_host_name', "The app host name (#{n}) specified by `#{consumer.spec.name}` could " \
414
+ 'not be found. You must explicitly declare a dependency on that app spec.')
415
+ end
416
+ end
417
+
397
418
  # Performs validations related to the `script_phases` attribute.
398
419
  #
399
420
  def _validate_script_phases(s)
@@ -482,6 +503,15 @@ module Pod
482
503
  end
483
504
  end
484
505
 
506
+ # @param [Hash,Object] value
507
+ #
508
+ def _validate_info_plist(value)
509
+ return if value.empty?
510
+ if consumer.spec.subspec? && consumer.spec.library_specification?
511
+ results.add_error('info_plist', 'Info.plist configuration is not currently supported for subspecs.')
512
+ end
513
+ end
514
+
485
515
  #-----------------------------------------------------------------------#
486
516
 
487
517
  # @!group All specs validation helpers
@@ -181,6 +181,10 @@ module Pod
181
181
  end
182
182
 
183
183
  def validate_attribute_hash_keys(attribute, value)
184
+ unless value.is_a?(Hash)
185
+ results.add_error(attribute.name, "Unsupported type `#{value.class}`, expected `Hash`")
186
+ return
187
+ end
184
188
  major_keys = value.keys & attribute.keys.keys
185
189
  if major_keys.count.zero?
186
190
  results.add_warning('keys', "Missing primary key for `#{attribute.name}` " \
@@ -27,11 +27,6 @@ module Pod
27
27
 
28
28
  # @return [Version] The version of the Pod.
29
29
  #
30
- # @todo The version is memoized because the Resolvers sets the head
31
- # state on it. This information should be stored in the
32
- # specification instance and the lockfile should have a more
33
- # robust handling of head versions (like a dedicated section).
34
- #
35
30
  def version
36
31
  if root?
37
32
  @version ||= Version.new(attributes_hash['version'])
@@ -131,7 +126,12 @@ module Pod
131
126
  # should be retrieved.
132
127
  #
133
128
  def source
134
- Specification.convert_keys_to_symbol(attributes_hash['source'])
129
+ value = attributes_hash['source']
130
+ if value && value.is_a?(Hash)
131
+ Specification.convert_keys_to_symbol(value)
132
+ else
133
+ value
134
+ end
135
135
  end
136
136
 
137
137
  # @return [String] A short description of the Pod.
@@ -0,0 +1,14 @@
1
+ module Pod
2
+ class TrunkSource < CDNSource
3
+ # On-disk master repo name
4
+ TRUNK_REPO_NAME = 'trunk'.freeze
5
+
6
+ # Remote CDN repo URL
7
+ TRUNK_REPO_URL = 'https://cdn.cocoapods.org/'.freeze
8
+
9
+ def url
10
+ @url ||= TRUNK_REPO_URL
11
+ super
12
+ end
13
+ end
14
+ end
@@ -68,7 +68,8 @@ module Pod
68
68
  # For more info, see: http://semver.org
69
69
  #
70
70
  def prerelease?
71
- @prerelease ||= @version =~ /[a-zA-Z\-]/
71
+ return @prerelease if defined?(@prerelease)
72
+ @prerelease = @version =~ /[a-zA-Z\-]/
72
73
  end
73
74
 
74
75
  # @return [Bool] Whether a string representation is correct.
@@ -205,7 +206,7 @@ module Pod
205
206
  compare = proc do |segments, other_segments, is_pre_release|
206
207
  limit = [segments.size, other_segments.size].max
207
208
 
208
- (0..limit).each do |i|
209
+ 0.upto(limit) do |i|
209
210
  lhs = segments[i]
210
211
  rhs = other_segments[i]
211
212
 
@@ -224,8 +225,6 @@ module Pod
224
225
  if comparison = lhs <=> rhs
225
226
  return comparison
226
227
  end
227
- return 1 if lhs.is_a?(String) && rhs.is_a?(Numeric)
228
- return -1 if lhs.is_a?(Numeric) && rhs.is_a?(String)
229
228
  end
230
229
  end
231
230
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocoapods-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.7.5
4
+ version: 1.8.0.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eloy Duran
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-07-19 00:00:00.000000000 Z
12
+ date: 2019-08-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -59,6 +59,20 @@ dependencies:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
61
  version: 2.0.4
62
+ - !ruby/object:Gem::Dependency
63
+ name: algoliasearch
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.0'
69
+ type: :runtime
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.0'
62
76
  - !ruby/object:Gem::Dependency
63
77
  name: bacon
64
78
  requirement: !ruby/object:Gem::Requirement
@@ -94,7 +108,6 @@ files:
94
108
  - lib/cocoapods-core/github.rb
95
109
  - lib/cocoapods-core/http.rb
96
110
  - lib/cocoapods-core/lockfile.rb
97
- - lib/cocoapods-core/master_source.rb
98
111
  - lib/cocoapods-core/metrics.rb
99
112
  - lib/cocoapods-core/platform.rb
100
113
  - lib/cocoapods-core/podfile.rb
@@ -122,6 +135,7 @@ files:
122
135
  - lib/cocoapods-core/specification/set.rb
123
136
  - lib/cocoapods-core/specification/set/presenter.rb
124
137
  - lib/cocoapods-core/standard_error.rb
138
+ - lib/cocoapods-core/trunk_source.rb
125
139
  - lib/cocoapods-core/vendor.rb
126
140
  - lib/cocoapods-core/vendor/requirement.rb
127
141
  - lib/cocoapods-core/vendor/version.rb
@@ -1,8 +0,0 @@
1
- module Pod
2
- class MasterSource < Source
3
- # For now, the MasterSource behaves exactly the same as any other Source.
4
- # In the future we may apply separate logic to the MasterSource that doesn't
5
- # depend on the file system.
6
- MASTER_REPO_NAME = 'master'.freeze
7
- end
8
- end