xcocoapods 1.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +6303 -0
  3. data/LICENSE +28 -0
  4. data/README.md +80 -0
  5. data/bin/pod +56 -0
  6. data/bin/sandbox-pod +168 -0
  7. data/lib/cocoapods.rb +73 -0
  8. data/lib/cocoapods/command.rb +175 -0
  9. data/lib/cocoapods/command/cache.rb +28 -0
  10. data/lib/cocoapods/command/cache/clean.rb +90 -0
  11. data/lib/cocoapods/command/cache/list.rb +69 -0
  12. data/lib/cocoapods/command/env.rb +66 -0
  13. data/lib/cocoapods/command/init.rb +128 -0
  14. data/lib/cocoapods/command/install.rb +45 -0
  15. data/lib/cocoapods/command/ipc.rb +19 -0
  16. data/lib/cocoapods/command/ipc/list.rb +40 -0
  17. data/lib/cocoapods/command/ipc/podfile.rb +31 -0
  18. data/lib/cocoapods/command/ipc/podfile_json.rb +30 -0
  19. data/lib/cocoapods/command/ipc/repl.rb +51 -0
  20. data/lib/cocoapods/command/ipc/spec.rb +29 -0
  21. data/lib/cocoapods/command/ipc/update_search_index.rb +24 -0
  22. data/lib/cocoapods/command/lib.rb +11 -0
  23. data/lib/cocoapods/command/lib/create.rb +105 -0
  24. data/lib/cocoapods/command/lib/lint.rb +121 -0
  25. data/lib/cocoapods/command/list.rb +39 -0
  26. data/lib/cocoapods/command/options/project_directory.rb +36 -0
  27. data/lib/cocoapods/command/options/repo_update.rb +34 -0
  28. data/lib/cocoapods/command/outdated.rb +140 -0
  29. data/lib/cocoapods/command/repo.rb +29 -0
  30. data/lib/cocoapods/command/repo/add.rb +103 -0
  31. data/lib/cocoapods/command/repo/lint.rb +82 -0
  32. data/lib/cocoapods/command/repo/list.rb +93 -0
  33. data/lib/cocoapods/command/repo/push.rb +281 -0
  34. data/lib/cocoapods/command/repo/remove.rb +36 -0
  35. data/lib/cocoapods/command/repo/update.rb +28 -0
  36. data/lib/cocoapods/command/setup.rb +103 -0
  37. data/lib/cocoapods/command/spec.rb +112 -0
  38. data/lib/cocoapods/command/spec/cat.rb +51 -0
  39. data/lib/cocoapods/command/spec/create.rb +283 -0
  40. data/lib/cocoapods/command/spec/edit.rb +87 -0
  41. data/lib/cocoapods/command/spec/env_spec.rb +53 -0
  42. data/lib/cocoapods/command/spec/lint.rb +137 -0
  43. data/lib/cocoapods/command/spec/which.rb +43 -0
  44. data/lib/cocoapods/command/update.rb +101 -0
  45. data/lib/cocoapods/config.rb +347 -0
  46. data/lib/cocoapods/core_overrides.rb +1 -0
  47. data/lib/cocoapods/downloader.rb +190 -0
  48. data/lib/cocoapods/downloader/cache.rb +233 -0
  49. data/lib/cocoapods/downloader/request.rb +86 -0
  50. data/lib/cocoapods/downloader/response.rb +16 -0
  51. data/lib/cocoapods/executable.rb +222 -0
  52. data/lib/cocoapods/external_sources.rb +57 -0
  53. data/lib/cocoapods/external_sources/abstract_external_source.rb +205 -0
  54. data/lib/cocoapods/external_sources/downloader_source.rb +30 -0
  55. data/lib/cocoapods/external_sources/path_source.rb +55 -0
  56. data/lib/cocoapods/external_sources/podspec_source.rb +54 -0
  57. data/lib/cocoapods/gem_version.rb +5 -0
  58. data/lib/cocoapods/generator/acknowledgements.rb +107 -0
  59. data/lib/cocoapods/generator/acknowledgements/markdown.rb +44 -0
  60. data/lib/cocoapods/generator/acknowledgements/plist.rb +94 -0
  61. data/lib/cocoapods/generator/app_target_helper.rb +244 -0
  62. data/lib/cocoapods/generator/bridge_support.rb +22 -0
  63. data/lib/cocoapods/generator/constant.rb +19 -0
  64. data/lib/cocoapods/generator/copy_resources_script.rb +230 -0
  65. data/lib/cocoapods/generator/dummy_source.rb +31 -0
  66. data/lib/cocoapods/generator/embed_frameworks_script.rb +215 -0
  67. data/lib/cocoapods/generator/header.rb +103 -0
  68. data/lib/cocoapods/generator/info_plist_file.rb +116 -0
  69. data/lib/cocoapods/generator/module_map.rb +99 -0
  70. data/lib/cocoapods/generator/prefix_header.rb +60 -0
  71. data/lib/cocoapods/generator/umbrella_header.rb +46 -0
  72. data/lib/cocoapods/hooks_manager.rb +132 -0
  73. data/lib/cocoapods/installer.rb +703 -0
  74. data/lib/cocoapods/installer/analyzer.rb +972 -0
  75. data/lib/cocoapods/installer/analyzer/analysis_result.rb +87 -0
  76. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +98 -0
  77. data/lib/cocoapods/installer/analyzer/pod_variant.rb +67 -0
  78. data/lib/cocoapods/installer/analyzer/pod_variant_set.rb +157 -0
  79. data/lib/cocoapods/installer/analyzer/podfile_dependency_cache.rb +54 -0
  80. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +240 -0
  81. data/lib/cocoapods/installer/analyzer/specs_state.rb +84 -0
  82. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +53 -0
  83. data/lib/cocoapods/installer/analyzer/target_inspector.rb +260 -0
  84. data/lib/cocoapods/installer/installation_options.rb +158 -0
  85. data/lib/cocoapods/installer/pod_source_installer.rb +202 -0
  86. data/lib/cocoapods/installer/pod_source_preparer.rb +77 -0
  87. data/lib/cocoapods/installer/podfile_validator.rb +139 -0
  88. data/lib/cocoapods/installer/post_install_hooks_context.rb +132 -0
  89. data/lib/cocoapods/installer/pre_install_hooks_context.rb +51 -0
  90. data/lib/cocoapods/installer/source_provider_hooks_context.rb +34 -0
  91. data/lib/cocoapods/installer/user_project_integrator.rb +250 -0
  92. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +463 -0
  93. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +146 -0
  94. data/lib/cocoapods/installer/xcode.rb +8 -0
  95. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +416 -0
  96. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +181 -0
  97. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +84 -0
  98. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +334 -0
  99. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +777 -0
  100. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +116 -0
  101. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +86 -0
  102. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +256 -0
  103. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +68 -0
  104. data/lib/cocoapods/installer/xcode/target_validator.rb +147 -0
  105. data/lib/cocoapods/open-uri.rb +33 -0
  106. data/lib/cocoapods/project.rb +414 -0
  107. data/lib/cocoapods/resolver.rb +585 -0
  108. data/lib/cocoapods/resolver/lazy_specification.rb +79 -0
  109. data/lib/cocoapods/sandbox.rb +404 -0
  110. data/lib/cocoapods/sandbox/file_accessor.rb +444 -0
  111. data/lib/cocoapods/sandbox/headers_store.rb +146 -0
  112. data/lib/cocoapods/sandbox/path_list.rb +220 -0
  113. data/lib/cocoapods/sandbox/pod_dir_cleaner.rb +85 -0
  114. data/lib/cocoapods/sandbox/podspec_finder.rb +23 -0
  115. data/lib/cocoapods/sources_manager.rb +157 -0
  116. data/lib/cocoapods/target.rb +261 -0
  117. data/lib/cocoapods/target/aggregate_target.rb +338 -0
  118. data/lib/cocoapods/target/build_settings.rb +1075 -0
  119. data/lib/cocoapods/target/pod_target.rb +559 -0
  120. data/lib/cocoapods/user_interface.rb +459 -0
  121. data/lib/cocoapods/user_interface/error_report.rb +187 -0
  122. data/lib/cocoapods/user_interface/inspector_reporter.rb +109 -0
  123. data/lib/cocoapods/validator.rb +981 -0
  124. metadata +533 -0
@@ -0,0 +1,158 @@
1
+ require 'active_support/hash_with_indifferent_access'
2
+
3
+ module Pod
4
+ class Installer
5
+ # Represents the installation options the user can customize via a
6
+ # `Podfile`.
7
+ #
8
+ class InstallationOptions
9
+ # Parses installation options from a podfile.
10
+ #
11
+ # @param [Podfile] podfile the podfile to parse installation options
12
+ # from.
13
+ #
14
+ # @raise [Informative] if `podfile` does not specify a `CocoaPods`
15
+ # install.
16
+ #
17
+ # @return [Self]
18
+ #
19
+ def self.from_podfile(podfile)
20
+ name, options = podfile.installation_method
21
+ unless name.downcase == 'cocoapods'
22
+ raise Informative, "Currently need to specify a `cocoapods` install, you chose `#{name}`."
23
+ end
24
+ new(options)
25
+ end
26
+
27
+ # Defines a new installation option.
28
+ #
29
+ # @param [#to_s] name the name of the option.
30
+ #
31
+ # @param default the default value for the option.
32
+ #
33
+ # @param [Boolean] boolean whether the option has a boolean value.
34
+ #
35
+ # @return [void]
36
+ #
37
+ # @!macro [attach] option
38
+ #
39
+ # @note this option defaults to $2.
40
+ #
41
+ # @return the $1 $0 for installation.
42
+ #
43
+ def self.option(name, default, boolean: true)
44
+ name = name.to_s
45
+ raise ArgumentError, "The `#{name}` option is already defined" if defaults.key?(name)
46
+ defaults[name] = default
47
+ attr_accessor name
48
+ alias_method "#{name}?", name if boolean
49
+ end
50
+
51
+ # @return [Hash<Symbol,Object>] all known installation options and their
52
+ # default values.
53
+ #
54
+ def self.defaults
55
+ @defaults ||= {}
56
+ end
57
+
58
+ # @return [Array<Symbol>] the names of all known installation options.
59
+ #
60
+ def self.all_options
61
+ defaults.keys
62
+ end
63
+
64
+ # Initializes the installation options with a hash of options from a
65
+ # Podfile.
66
+ #
67
+ # @param [Hash] options the options to parse.
68
+ #
69
+ # @raise [Informative] if `options` contains any unknown keys.
70
+ #
71
+ def initialize(options = {})
72
+ options = ActiveSupport::HashWithIndifferentAccess.new(options)
73
+ unknown_keys = options.keys - self.class.all_options.map(&:to_s)
74
+ raise Informative, "Unknown installation options: #{unknown_keys.to_sentence}." unless unknown_keys.empty?
75
+ self.class.defaults.each do |key, default|
76
+ value = options.fetch(key, default)
77
+ send("#{key}=", value)
78
+ end
79
+ end
80
+
81
+ # @param [Boolean] include_defaults whether values that match the default
82
+ # for their option should be included. Defaults to `true`.
83
+ #
84
+ # @return [Hash] the options, keyed by option name.
85
+ #
86
+ def to_h(include_defaults: true)
87
+ self.class.defaults.reduce(ActiveSupport::HashWithIndifferentAccess.new) do |hash, (option, default)|
88
+ value = send(option)
89
+ hash[option] = value if include_defaults || value != default
90
+ hash
91
+ end
92
+ end
93
+
94
+ def ==(other)
95
+ other.is_a?(self.class) && to_h == other.to_h
96
+ end
97
+
98
+ alias_method :eql, :==
99
+
100
+ def hash
101
+ to_h.hash
102
+ end
103
+
104
+ option :clean, true
105
+ option :deduplicate_targets, true
106
+ option :deterministic_uuids, true
107
+ option :integrate_targets, true
108
+ option :lock_pod_sources, true
109
+ option :warn_for_multiple_pod_sources, true
110
+ option :share_schemes_for_development_pods, false
111
+
112
+ module Mixin
113
+ module ClassMethods
114
+ # Delegates the creation of {#installation_options} to the `Podfile`
115
+ # returned by the given block.
116
+ #
117
+ # @param blk a block that returns the `Podfile` to create
118
+ # installation options from.
119
+ #
120
+ # @return [Void]
121
+ #
122
+ def delegate_installation_options(&blk)
123
+ define_method(:installation_options) do
124
+ @installation_options ||= InstallationOptions.from_podfile(instance_eval(&blk))
125
+ end
126
+ end
127
+
128
+ # Delegates the installation options attributes directly to
129
+ # {#installation_options}.
130
+ #
131
+ # @return [Void]
132
+ #
133
+ def delegate_installation_option_attributes!
134
+ define_method(:respond_to_missing?) do |name, *args|
135
+ installation_options.respond_to?(name, *args) || super
136
+ end
137
+
138
+ define_method(:method_missing) do |name, *args, &blk|
139
+ if installation_options.respond_to?(name)
140
+ installation_options.send(name, *args, &blk)
141
+ else
142
+ super
143
+ end
144
+ end
145
+ end
146
+ end
147
+
148
+ # @return [InstallationOptions] The installation options.
149
+ #
150
+ attr_accessor :installation_options
151
+
152
+ def self.included(mod)
153
+ mod.extend(ClassMethods)
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,202 @@
1
+ require 'active_support/core_ext/string/strip'
2
+
3
+ module Pod
4
+ class Installer
5
+ # Controller class responsible of installing the activated specifications
6
+ # of a single Pod.
7
+ #
8
+ # @note This class needs to consider all the activated specs of a Pod.
9
+ #
10
+ class PodSourceInstaller
11
+ UNENCRYPTED_PROTOCOLS = %w(http git).freeze
12
+
13
+ # @return [Sandbox] The installation target.
14
+ #
15
+ attr_reader :sandbox
16
+
17
+ # @return [Hash{Symbol=>Array}] The specifications that need to be
18
+ # installed grouped by platform.
19
+ #
20
+ attr_reader :specs_by_platform
21
+
22
+ # @return [Boolean] Whether the installer is allowed to touch the cache.
23
+ #
24
+ attr_reader :can_cache
25
+ alias_method :can_cache?, :can_cache
26
+
27
+ # Initialize a new instance
28
+ #
29
+ # @param [Sandbox] sandbox @see #sandbox
30
+ # @param [Hash{Symbol=>Array}] specs_by_platform @see #specs_by_platform
31
+ # @param [Boolean] can_cache @see #can_cache
32
+ #
33
+ def initialize(sandbox, specs_by_platform, can_cache: true)
34
+ @sandbox = sandbox
35
+ @specs_by_platform = specs_by_platform
36
+ @can_cache = can_cache
37
+ end
38
+
39
+ # @return [String] A string suitable for debugging.
40
+ #
41
+ def inspect
42
+ "<#{self.class} sandbox=#{sandbox.root} pod=#{root_spec.name}"
43
+ end
44
+
45
+ # @return [String] The name of the pod this installer is installing.
46
+ #
47
+ def name
48
+ root_spec.name
49
+ end
50
+
51
+ #-----------------------------------------------------------------------#
52
+
53
+ public
54
+
55
+ # @!group Installation
56
+
57
+ # Creates the target in the Pods project and the relative support files.
58
+ #
59
+ # @return [void]
60
+ #
61
+ def install!
62
+ download_source unless predownloaded? || local?
63
+ PodSourcePreparer.new(root_spec, root).prepare! if local?
64
+ end
65
+
66
+ # Cleans the installations if appropriate.
67
+ #
68
+ # @return [void]
69
+ #
70
+ def clean!
71
+ clean_installation unless local?
72
+ end
73
+
74
+ # Locks the source files if appropriate.
75
+ #
76
+ # @return [void]
77
+ #
78
+ def lock_files!(file_accessors)
79
+ return if local?
80
+ FileUtils.chmod('u-w', source_files(file_accessors))
81
+ end
82
+
83
+ # Unlocks the source files if appropriate.
84
+ #
85
+ # @return [void]
86
+ #
87
+ def unlock_files!(file_accessors)
88
+ return if local?
89
+ FileUtils.chmod('u+w', source_files(file_accessors))
90
+ end
91
+
92
+ #-----------------------------------------------------------------------#
93
+
94
+ private
95
+
96
+ # @!group Installation Steps
97
+
98
+ # Downloads the source of the Pod.
99
+ #
100
+ # @return [void]
101
+ #
102
+ def download_source
103
+ verify_source_is_secure(root_spec)
104
+ download_result = Downloader.download(download_request, root, :can_cache => can_cache?)
105
+
106
+ if (specific_source = download_result.checkout_options) && specific_source != root_spec.source
107
+ sandbox.store_checkout_source(root_spec.name, specific_source)
108
+ end
109
+ end
110
+
111
+ # Verify the source of the spec is secure, which is used to show a warning to the user if that isn't the case
112
+ # This method doesn't verify all protocols, but currently only prohibits unencrypted 'http://' and 'git://''
113
+ # connections.
114
+ #
115
+ # @return [void]
116
+ #
117
+ def verify_source_is_secure(root_spec)
118
+ return if root_spec.source.nil? || (root_spec.source[:http].nil? && root_spec.source[:git].nil?)
119
+ source = if !root_spec.source[:http].nil?
120
+ URI(root_spec.source[:http].to_s)
121
+ elsif !root_spec.source[:git].nil?
122
+ git_source = root_spec.source[:git].to_s
123
+ return unless git_source =~ /^#{URI.regexp}$/
124
+ URI(git_source)
125
+ end
126
+ if UNENCRYPTED_PROTOCOLS.include?(source.scheme)
127
+ UI.warn "'#{root_spec.name}' uses the unencrypted '#{source.scheme}' protocol to transfer the Pod. " \
128
+ 'Please be sure you\'re in a safe network with only trusted hosts. ' \
129
+ 'Otherwise, please reach out to the library author to notify them of this security issue.'
130
+ end
131
+ end
132
+
133
+ def download_request
134
+ Downloader::Request.new(
135
+ :spec => root_spec,
136
+ :released => released?,
137
+ )
138
+ end
139
+
140
+ # Removes all the files not needed for the installation according to the
141
+ # specs by platform.
142
+ #
143
+ # @return [void]
144
+ #
145
+ def clean_installation
146
+ cleaner = Sandbox::PodDirCleaner.new(root, specs_by_platform)
147
+ cleaner.clean!
148
+ end
149
+
150
+ #-----------------------------------------------------------------------#
151
+
152
+ private
153
+
154
+ # @!group Convenience methods.
155
+
156
+ # @return [Array<Specifications>] the specification of the Pod used in
157
+ # this installation.
158
+ #
159
+ def specs
160
+ specs_by_platform.values.flatten
161
+ end
162
+
163
+ # @return [Specification] the root specification of the Pod.
164
+ #
165
+ def root_spec
166
+ specs.first.root
167
+ end
168
+
169
+ # @return [Pathname] the folder where the source of the Pod is located.
170
+ #
171
+ def root
172
+ sandbox.pod_dir(root_spec.name)
173
+ end
174
+
175
+ # @return [Boolean] whether the source has been pre downloaded in the
176
+ # resolution process to retrieve its podspec.
177
+ #
178
+ def predownloaded?
179
+ sandbox.predownloaded_pods.include?(root_spec.name)
180
+ end
181
+
182
+ # @return [Boolean] whether the pod uses the local option and thus
183
+ # CocoaPods should not interfere with the files of the user.
184
+ #
185
+ def local?
186
+ sandbox.local?(root_spec.name)
187
+ end
188
+
189
+ def released?
190
+ !local? && !predownloaded? && sandbox.specification(root_spec.name) != root_spec
191
+ end
192
+
193
+ # @return [Array<Pathname>] The paths of the source files
194
+ #
195
+ def source_files(file_accessors)
196
+ file_accessors.flat_map(&:source_files)
197
+ end
198
+
199
+ #-----------------------------------------------------------------------#
200
+ end
201
+ end
202
+ end
@@ -0,0 +1,77 @@
1
+ module Pod
2
+ class Installer
3
+ # Controller class responsible of executing the prepare command
4
+ # of a single Pod.
5
+ #
6
+ class PodSourcePreparer
7
+ # @return [Specification] the root specification of the Pod.
8
+ #
9
+ attr_reader :spec
10
+
11
+ # @return [Pathname] the folder where the source of the Pod is located.
12
+ #
13
+ attr_reader :path
14
+
15
+ # Initialize a new instance
16
+ #
17
+ # @param [Specification] spec the root specification of the Pod.
18
+ # @param [Pathname] path the folder where the source of the Pod is located.
19
+ #
20
+ def initialize(spec, path)
21
+ raise "Given spec isn't a root spec, but must be." unless spec.root?
22
+ @spec = spec
23
+ @path = path
24
+ end
25
+
26
+ #-----------------------------------------------------------------------#
27
+
28
+ public
29
+
30
+ # @!group Preparation
31
+
32
+ # Executes the prepare command if there is one.
33
+ #
34
+ # @return [void]
35
+ #
36
+ def prepare!
37
+ run_prepare_command
38
+ end
39
+
40
+ #-----------------------------------------------------------------------#
41
+
42
+ private
43
+
44
+ # @!group Preparation Steps
45
+
46
+ extend Executable
47
+ executable :bash
48
+
49
+ # Runs the prepare command bash script of the spec.
50
+ #
51
+ # @note Unsets the `CDPATH` env variable before running the
52
+ # shell script to avoid issues with relative paths
53
+ # (issue #1694).
54
+ #
55
+ # @return [void]
56
+ #
57
+ def run_prepare_command
58
+ return unless spec.prepare_command
59
+ UI.section(' > Running prepare command', '', 1) do
60
+ Dir.chdir(path) do
61
+ begin
62
+ ENV.delete('CDPATH')
63
+ ENV['COCOAPODS_VERSION'] = Pod::VERSION
64
+ prepare_command = spec.prepare_command.strip_heredoc.chomp
65
+ full_command = "\nset -e\n" + prepare_command
66
+ bash!('-c', full_command)
67
+ ensure
68
+ ENV.delete('COCOAPODS_VERSION')
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ #-----------------------------------------------------------------------#
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,139 @@
1
+ module Pod
2
+ class Installer
3
+ # Validate the podfile before installing to catch errors and
4
+ # problems
5
+ #
6
+ class PodfileValidator
7
+ # @return [Podfile] The podfile being validated
8
+ #
9
+ attr_reader :podfile
10
+
11
+ # @return [Array<String>] any errors that have occured during the validation
12
+ #
13
+ attr_reader :errors
14
+
15
+ # @return [Array<String>] any warnings that have occured during the validation
16
+ #
17
+ attr_reader :warnings
18
+
19
+ # Initialize a new instance
20
+ #
21
+ # @param [Podfile] podfile
22
+ # The podfile to validate
23
+ #
24
+ # @param [Analyzer::PodfileDependencyCache] podfile_dependency_cache
25
+ # An (optional) cache of all the dependencies in the podfile
26
+ #
27
+ def initialize(podfile, podfile_dependency_cache = Analyzer::PodfileDependencyCache.from_podfile(podfile))
28
+ @podfile = podfile
29
+ @podfile_dependency_cache = podfile_dependency_cache
30
+ @errors = []
31
+ @warnings = []
32
+ @validated = false
33
+ end
34
+
35
+ # Validate the podfile
36
+ # Errors are added to the errors array
37
+ #
38
+ def validate
39
+ validate_pod_directives
40
+ validate_no_abstract_only_pods!
41
+ validate_dependencies_are_present!
42
+ validate_no_duplicate_targets!
43
+
44
+ @validated = true
45
+ end
46
+
47
+ # Wether the podfile is valid is not
48
+ # NOTE: Will execute `validate` if the podfile
49
+ # has not yet been validated
50
+ #
51
+ def valid?
52
+ validate unless @validated
53
+
54
+ @validated && errors.empty?
55
+ end
56
+
57
+ # A message describing any errors in the
58
+ # validation
59
+ #
60
+ def message
61
+ errors.join("\n")
62
+ end
63
+
64
+ private
65
+
66
+ def add_error(error)
67
+ errors << error
68
+ end
69
+
70
+ def add_warning(warning)
71
+ warnings << warning
72
+ end
73
+
74
+ def validate_pod_directives
75
+ @podfile_dependency_cache.podfile_dependencies.each do |dependency|
76
+ validate_conflicting_external_sources!(dependency)
77
+ end
78
+ end
79
+
80
+ def validate_conflicting_external_sources!(dependency)
81
+ external_source = dependency.external_source
82
+ return false if external_source.nil?
83
+
84
+ available_downloaders = Downloader.downloader_class_by_key.keys
85
+ specified_downloaders = external_source.select { |key| available_downloaders.include?(key) }
86
+ if specified_downloaders.size > 1
87
+ add_error "The dependency `#{dependency.name}` specifies more than one download strategy(#{specified_downloaders.keys.join(',')})." \
88
+ 'Only one is allowed'
89
+ end
90
+
91
+ pod_spec_or_path = external_source[:podspec].present? || external_source[:path].present?
92
+ if pod_spec_or_path && specified_downloaders.size > 0
93
+ add_error "The dependency `#{dependency.name}` specifies `podspec` or `path` in combination with other" \
94
+ ' download strategies. This is not allowed'
95
+ end
96
+ end
97
+
98
+ # Warns the user if the podfile is empty.
99
+ #
100
+ # @note The workspace is created in any case and all the user projects
101
+ # are added to it, however the projects are not integrated as
102
+ # there is no way to discern between target definitions which are
103
+ # empty and target definitions which just serve the purpose to
104
+ # wrap other ones. This is not an issue because empty target
105
+ # definitions generate empty libraries.
106
+ #
107
+ # @return [void]
108
+ #
109
+ def validate_dependencies_are_present!
110
+ if @podfile_dependency_cache.target_definition_list.all?(&:empty?)
111
+ add_warning 'The Podfile does not contain any dependencies.'
112
+ end
113
+ end
114
+
115
+ # Verifies that no dependencies in the Podfile will end up not being built
116
+ # at all. In other words, all dependencies _must_ belong to a non-abstract
117
+ # target, or be inherited by a target where `inheritance == complete`.
118
+ #
119
+ def validate_no_abstract_only_pods!
120
+ all_dependencies = @podfile_dependency_cache.podfile_dependencies
121
+ concrete_dependencies = @podfile_dependency_cache.target_definition_list.reject(&:abstract?).flat_map { |td| @podfile_dependency_cache.target_definition_dependencies(td) }
122
+ abstract_only_dependencies = all_dependencies - concrete_dependencies
123
+ abstract_only_dependencies.each do |dep|
124
+ add_error "The dependency `#{dep}` is not used in any concrete target."
125
+ end
126
+ end
127
+
128
+ def validate_no_duplicate_targets!
129
+ @podfile_dependency_cache.target_definition_list.group_by { |td| [td.name, td.user_project_path] }.
130
+ each do |(name, project), definitions|
131
+ next unless definitions.size > 1
132
+ error = "The target `#{name}` is declared twice"
133
+ error << " for the project `#{project}`" if project
134
+ add_error(error << '.')
135
+ end
136
+ end
137
+ end
138
+ end
139
+ end