cocoapods-core 0.17.0.rc5 → 0.17.0.rc6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +16 -8
- data/lib/cocoapods-core.rb +1 -0
- data/lib/cocoapods-core/core_ui.rb +8 -8
- data/lib/cocoapods-core/dependency.rb +7 -4
- data/lib/cocoapods-core/gem_version.rb +1 -1
- data/lib/cocoapods-core/lockfile.rb +12 -22
- data/lib/cocoapods-core/platform.rb +1 -1
- data/lib/cocoapods-core/podfile.rb +8 -3
- data/lib/cocoapods-core/podfile/dsl.rb +1 -3
- data/lib/cocoapods-core/podfile/target_definition.rb +1 -5
- data/lib/cocoapods-core/source.rb +8 -112
- data/lib/cocoapods-core/source/acceptor.rb +159 -0
- data/lib/cocoapods-core/source/aggregate.rb +229 -0
- data/lib/cocoapods-core/source/health_reporter.rb +208 -0
- data/lib/cocoapods-core/specification.rb +11 -5
- data/lib/cocoapods-core/specification/consumer.rb +1 -7
- data/lib/cocoapods-core/specification/dsl.rb +4 -3
- data/lib/cocoapods-core/specification/dsl/deprecations.rb +9 -4
- data/lib/cocoapods-core/specification/linter.rb +52 -29
- data/lib/cocoapods-core/specification/set/presenter.rb +2 -2
- data/lib/cocoapods-core/version.rb +3 -0
- data/lib/cocoapods-core/yaml_converter.rb +2 -13
- metadata +5 -3
- data/lib/cocoapods-core/source/validator.rb +0 -183
@@ -0,0 +1,159 @@
|
|
1
|
+
module Pod
|
2
|
+
class Source
|
3
|
+
|
4
|
+
# Checks whether a podspec can be accepted by a source. The check takes
|
5
|
+
# into account the introduction of 0.0.1 version if there are already
|
6
|
+
# tagged ones or whether there is change in the source.
|
7
|
+
#
|
8
|
+
class Acceptor
|
9
|
+
|
10
|
+
# @return [Source] the source where the podspec should be added.
|
11
|
+
#
|
12
|
+
attr_reader :source
|
13
|
+
|
14
|
+
# @param [Pathname] repo @see Source#repo.
|
15
|
+
#
|
16
|
+
def initialize(repo)
|
17
|
+
@source = Source.new(repo)
|
18
|
+
end
|
19
|
+
|
20
|
+
public
|
21
|
+
|
22
|
+
# @!group Actions
|
23
|
+
#-----------------------------------------------------------------------#
|
24
|
+
|
25
|
+
# Checks whether the given specification can be accepted.
|
26
|
+
#
|
27
|
+
# @return [Array<String>] A list of errors. If the list is empty the
|
28
|
+
# specification should be accepted.
|
29
|
+
#
|
30
|
+
def analyze(spec, previous_spec = nil)
|
31
|
+
errors = []
|
32
|
+
check_spec_source_change(spec, errors)
|
33
|
+
check_if_untagged_version_is_acceptable(spec, errors)
|
34
|
+
check_commit_change_for_untagged_version(spec, previous_spec, errors)
|
35
|
+
check_dependencies(spec, errors)
|
36
|
+
errors
|
37
|
+
end
|
38
|
+
|
39
|
+
# Checks whether the specification at the given path can be accepted.
|
40
|
+
#
|
41
|
+
# @return [Array<String>] A list of errors. If the list is empty the
|
42
|
+
# specification should be accepted.
|
43
|
+
#
|
44
|
+
def analyze_path(spec_path)
|
45
|
+
spec = Specification.from_file(spec_path)
|
46
|
+
analyze(spec)
|
47
|
+
rescue
|
48
|
+
["Unable to load the specification."]
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# @!group Private helpers
|
54
|
+
#-----------------------------------------------------------------------#
|
55
|
+
|
56
|
+
# Checks whether the source of the proposed specification is different
|
57
|
+
# from the one of the reference specification.
|
58
|
+
#
|
59
|
+
# @return [void]
|
60
|
+
#
|
61
|
+
def check_spec_source_change(spec, errors)
|
62
|
+
return unless spec
|
63
|
+
return unless reference_spec(spec)
|
64
|
+
keys = Spec::DSL::SOURCE_KEYS.keys
|
65
|
+
source = spec.source.values_at(*keys).compact.first
|
66
|
+
old_source = reference_spec(spec).source.values_at(*keys).compact.first
|
67
|
+
unless source == old_source
|
68
|
+
errors << "The source of the spec doesn't match with the recorded ones." \
|
69
|
+
"Source: `#{source}`. Previous: `#{old_source}`.\n " \
|
70
|
+
"Please contact the specs repo maintainers if the library changed " \
|
71
|
+
"location."
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# Checks there are already tagged specifications if the specification has
|
76
|
+
# a git source and doesn't specify a tag (i.e. rejects 0.0.1 specs if
|
77
|
+
# they are not admissible anymore).
|
78
|
+
#
|
79
|
+
# @return [void]
|
80
|
+
#
|
81
|
+
def check_if_untagged_version_is_acceptable(spec, errors)
|
82
|
+
return if !spec.source[:git] || spec.source[:tag]
|
83
|
+
return unless related_specifications(spec)
|
84
|
+
has_tagged_spec = related_specifications(spec).any? { |s| s.version != '0.0.1' }
|
85
|
+
if has_tagged_spec
|
86
|
+
errors << "There is already at least one versioned specification so " \
|
87
|
+
"untagged versions cannot be accepted."
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# If the previous specification for the given file is passed it is
|
92
|
+
# checked for any attempt to update the commit of a 0.0.1 version.
|
93
|
+
#
|
94
|
+
# @return [void]
|
95
|
+
#
|
96
|
+
def check_commit_change_for_untagged_version(spec, previous_spec, errors)
|
97
|
+
return unless previous_spec
|
98
|
+
return unless spec.version == Version.new('0.0.1')
|
99
|
+
unless spec.source[:commit] == previous_spec.source[:commit]
|
100
|
+
errors << "Attempt to rewrite the commit of a 0.0.1 version."
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Checks that there is a specification available for the dependencies of
|
105
|
+
# the given specification.
|
106
|
+
#
|
107
|
+
# @return [void]
|
108
|
+
#
|
109
|
+
def check_dependencies(spec, errors)
|
110
|
+
spec.dependencies.each do |dep|
|
111
|
+
set = source.search(dep)
|
112
|
+
unless set && set.specification
|
113
|
+
errors << "Unable to find a specification for the `#{dep}` dependency."
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
# @!group Source helpers
|
121
|
+
#-----------------------------------------------------------------------#
|
122
|
+
|
123
|
+
# Returns the specifications related to the given spec.
|
124
|
+
#
|
125
|
+
# @param [Specification] spec
|
126
|
+
# The specification for which the siblings specs are needed.
|
127
|
+
#
|
128
|
+
# @return [Array<Specification>] The other specifications of the Pod.
|
129
|
+
#
|
130
|
+
# @return [Nil] If there are no other specifications stored.
|
131
|
+
#
|
132
|
+
def related_specifications(spec)
|
133
|
+
versions = source.versions(spec.name)
|
134
|
+
return unless versions
|
135
|
+
specs = versions.sort.map { |v| source.specification(spec.name, v) }
|
136
|
+
specs.delete(spec)
|
137
|
+
specs
|
138
|
+
end
|
139
|
+
|
140
|
+
# Returns the most representative specification for the Pod of the given
|
141
|
+
# spec.
|
142
|
+
#
|
143
|
+
# @param [Specification] spec
|
144
|
+
# The specification for which the representative spec is needed.
|
145
|
+
#
|
146
|
+
# @return [Specification] The specification with the highest version.
|
147
|
+
#
|
148
|
+
# @return [Nil] If there are no other specifications stored.
|
149
|
+
#
|
150
|
+
def reference_spec(spec)
|
151
|
+
specs = related_specifications(spec)
|
152
|
+
specs.last if specs
|
153
|
+
end
|
154
|
+
|
155
|
+
#-----------------------------------------------------------------------#
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,229 @@
|
|
1
|
+
module Pod
|
2
|
+
class Source
|
3
|
+
|
4
|
+
# The Aggregate manages a directory of sources repositories.
|
5
|
+
#
|
6
|
+
class Aggregate
|
7
|
+
|
8
|
+
# @return [Pathname] the directory were the repositories are stored.
|
9
|
+
#
|
10
|
+
attr_reader :repos_dir
|
11
|
+
|
12
|
+
# @param [Pathname] repos_dir @see repos_dir.
|
13
|
+
#
|
14
|
+
def initialize(repos_dir)
|
15
|
+
@repos_dir = repos_dir
|
16
|
+
end
|
17
|
+
|
18
|
+
# @return [Array<Source>] all the sources.
|
19
|
+
#
|
20
|
+
def all
|
21
|
+
@sources ||= dirs.map { |repo| Source.new(repo) }.sort_by(&:name)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Array<String>] the names of all the pods available.
|
25
|
+
#
|
26
|
+
def all_pods
|
27
|
+
all.map(&:pods).flatten.uniq
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Array<Set>] the sets for all the pods available.
|
31
|
+
#
|
32
|
+
# @note Implementation detail: The sources don't cache their values
|
33
|
+
# because they might change in response to an update. Therefore
|
34
|
+
# this method to prevent slowness caches the values before
|
35
|
+
# processing them.
|
36
|
+
#
|
37
|
+
def all_sets
|
38
|
+
pods_by_source = {}
|
39
|
+
all.each do |source|
|
40
|
+
pods_by_source[source] = source.pods
|
41
|
+
end
|
42
|
+
sources = pods_by_source.keys
|
43
|
+
pods = pods_by_source.values.flatten.uniq
|
44
|
+
|
45
|
+
pods.map do |pod|
|
46
|
+
pod_sources = sources.select{ |s| pods_by_source[s].include?(pod) }.compact
|
47
|
+
Specification::Set.new(pod, pod_sources)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# @return [Array<Pathname>] the directories where the sources are stored.
|
52
|
+
#
|
53
|
+
# @note If the repos dir doesn't exits this will return an empty array.
|
54
|
+
#
|
55
|
+
# @raise If the repos dir doesn't exits.
|
56
|
+
#
|
57
|
+
def dirs
|
58
|
+
if repos_dir.exist?
|
59
|
+
repos_dir.children.select(&:directory?)
|
60
|
+
else
|
61
|
+
[]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Returns a set configured with the source which contains the highest
|
66
|
+
# version in the aggregate.
|
67
|
+
#
|
68
|
+
# @param [String] name
|
69
|
+
# The name of the Pod.
|
70
|
+
#
|
71
|
+
# @return [Set] The most representative set for the Pod with the given
|
72
|
+
# name.
|
73
|
+
#
|
74
|
+
def represenative_set(name)
|
75
|
+
representative_source = nil
|
76
|
+
highest_version = nil
|
77
|
+
all.each do |source|
|
78
|
+
source_versions = source.versions(name)
|
79
|
+
if source_versions
|
80
|
+
source_version = source_versions.first
|
81
|
+
if highest_version.nil? || (highest_version < source_version)
|
82
|
+
highest_version = source_version
|
83
|
+
representative_source = source
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
Specification::Set.new(name, representative_source)
|
88
|
+
end
|
89
|
+
|
90
|
+
public
|
91
|
+
|
92
|
+
# @!group Search
|
93
|
+
#-----------------------------------------------------------------------#
|
94
|
+
|
95
|
+
# @return [Set, nil] a set for a given dependency including all the
|
96
|
+
# {Source} that contain the Pod. If no sources containing the
|
97
|
+
# Pod where found it returns nil.
|
98
|
+
#
|
99
|
+
# @raise If no source including the set can be found.
|
100
|
+
#
|
101
|
+
# @see Source#search
|
102
|
+
#
|
103
|
+
def search(dependency)
|
104
|
+
sources = all.select { |s| !s.search(dependency).nil? }
|
105
|
+
Specification::Set.new(dependency.root_name, sources) unless sources.empty?
|
106
|
+
end
|
107
|
+
|
108
|
+
# @return [Array<Set>] the sets that contain the search term.
|
109
|
+
#
|
110
|
+
# @raise If no source including the set can be found.
|
111
|
+
#
|
112
|
+
# @todo Clients should raise not this method.
|
113
|
+
#
|
114
|
+
# @see Source#search_by_name
|
115
|
+
#
|
116
|
+
def search_by_name(query, full_text_search = false)
|
117
|
+
pods_by_source = {}
|
118
|
+
result = []
|
119
|
+
all.each { |s| pods_by_source[s] = s.search_by_name(query, full_text_search).map(&:name) }
|
120
|
+
root_spec_names = pods_by_source.values.flatten.uniq
|
121
|
+
root_spec_names.each do |pod|
|
122
|
+
sources = []
|
123
|
+
pods_by_source.each{ |source, pods| sources << source if pods.include?(pod) }
|
124
|
+
result << Specification::Set.new(pod, sources)
|
125
|
+
end
|
126
|
+
if result.empty?
|
127
|
+
extra = ", author, summary, or description" if full_text_search
|
128
|
+
raise(Informative, "Unable to find a pod with name" \
|
129
|
+
"#{extra} matching `#{query}'")
|
130
|
+
end
|
131
|
+
result
|
132
|
+
end
|
133
|
+
|
134
|
+
public
|
135
|
+
|
136
|
+
# @!group Search Index
|
137
|
+
#-----------------------------------------------------------------------#
|
138
|
+
|
139
|
+
# Generates from scratch the search data for all the sources of the
|
140
|
+
# aggregate. This operation can take a considerable amount of time
|
141
|
+
# (seconds) as it needs to evaluate the most representative podspec
|
142
|
+
# for each Pod.
|
143
|
+
#
|
144
|
+
# @return [Hash{String=>Hash}] The search data of every set grouped by
|
145
|
+
# name.
|
146
|
+
#
|
147
|
+
def generate_search_index
|
148
|
+
result = {}
|
149
|
+
all_sets.each do |set|
|
150
|
+
result[set.name] = search_data_from_set(set)
|
151
|
+
end
|
152
|
+
result
|
153
|
+
end
|
154
|
+
|
155
|
+
# Updates inline the given search data with the information stored in all
|
156
|
+
# the sources. The update skips the Pods for which the version of the
|
157
|
+
# search data is the same of the highest version known to the aggregate.
|
158
|
+
# This can lead to updates in podspecs being skipped until a new version
|
159
|
+
# is released.
|
160
|
+
#
|
161
|
+
# @note This procedure is considerably faster as it only needs to
|
162
|
+
# load the most representative spec of the new or updated Pods.
|
163
|
+
#
|
164
|
+
# @return [Hash{String=>Hash}] The search data of every set grouped by
|
165
|
+
# name.
|
166
|
+
#
|
167
|
+
def update_search_index(search_data)
|
168
|
+
enumerated_names = []
|
169
|
+
all_sets.each do |set|
|
170
|
+
enumerated_names << set.name
|
171
|
+
set_data = search_data[set.name]
|
172
|
+
has_data = set_data && set_data['version']
|
173
|
+
needs_update = !has_data || Version.new(set_data['version']) < set.required_version
|
174
|
+
if needs_update
|
175
|
+
search_data[set.name] = search_data_from_set(set)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
stored_names = search_data.keys
|
180
|
+
delted_names = stored_names - enumerated_names
|
181
|
+
delted_names.each do |name|
|
182
|
+
search_data.delete(name)
|
183
|
+
end
|
184
|
+
|
185
|
+
search_data
|
186
|
+
end
|
187
|
+
|
188
|
+
private
|
189
|
+
|
190
|
+
# @!group Private helpers
|
191
|
+
#-----------------------------------------------------------------------#
|
192
|
+
|
193
|
+
# Returns the search related information from the most representative
|
194
|
+
# specification of the set following keys:
|
195
|
+
#
|
196
|
+
# - version
|
197
|
+
# - summary
|
198
|
+
# - description
|
199
|
+
# - authors
|
200
|
+
#
|
201
|
+
# @param [Set] set
|
202
|
+
# The set for which the information is needed.
|
203
|
+
#
|
204
|
+
# @note If the specification can't load an empty hash is returned and
|
205
|
+
# a warning is printed.
|
206
|
+
#
|
207
|
+
# @note For compatibility with non Ruby clients a strings are used
|
208
|
+
# instead of symbols for the keys.
|
209
|
+
#
|
210
|
+
# @return [Hash{String=>String}] A hash with the search information.
|
211
|
+
#
|
212
|
+
def search_data_from_set(set)
|
213
|
+
result = {}
|
214
|
+
spec = set.specification
|
215
|
+
result['version'] = spec.version.to_s
|
216
|
+
result['summary'] = spec.summary
|
217
|
+
result['description'] = spec.description
|
218
|
+
result['authors'] = spec.authors.keys.sort * ', '
|
219
|
+
result
|
220
|
+
rescue
|
221
|
+
CoreUI.warn "Skipping `#{set.name}` because the podspec contains errors."
|
222
|
+
result
|
223
|
+
end
|
224
|
+
|
225
|
+
#-----------------------------------------------------------------------#
|
226
|
+
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,208 @@
|
|
1
|
+
module Pod
|
2
|
+
class Source
|
3
|
+
|
4
|
+
# Checks a source for errors and warnings.
|
5
|
+
#
|
6
|
+
class HealthReporter
|
7
|
+
|
8
|
+
# @return [Source] the source to check.
|
9
|
+
#
|
10
|
+
attr_reader :source
|
11
|
+
|
12
|
+
# @param [Pathname] repo @see Source#repo.
|
13
|
+
#
|
14
|
+
def initialize(repo)
|
15
|
+
@source = Source.new(repo)
|
16
|
+
@errors = {}
|
17
|
+
@linter_results = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Bool] Whether the more strict validation of the master repo
|
21
|
+
# should be used. Specifically The master repo treats certain
|
22
|
+
# warnings as errors.
|
23
|
+
#
|
24
|
+
attr_accessor :master_repo_mode
|
25
|
+
|
26
|
+
public
|
27
|
+
|
28
|
+
# @!group Configuration
|
29
|
+
#-----------------------------------------------------------------------#
|
30
|
+
|
31
|
+
# Allows to specify an optional callback which is called before
|
32
|
+
# analysing every spec. Suitable for UI.
|
33
|
+
#
|
34
|
+
# @param [Proc] A callback which is called before checking any
|
35
|
+
# specification. It receives the name and the version of the
|
36
|
+
# spec.
|
37
|
+
#
|
38
|
+
# @return [void]
|
39
|
+
#
|
40
|
+
def pre_check(&block)
|
41
|
+
@pre_check_callback = block
|
42
|
+
end
|
43
|
+
|
44
|
+
public
|
45
|
+
|
46
|
+
# @!group Actions
|
47
|
+
#-----------------------------------------------------------------------#
|
48
|
+
|
49
|
+
# Analyzes all the specification files in the source.
|
50
|
+
#
|
51
|
+
# @return [HealthReport] A report which contains the information about the
|
52
|
+
# state of the source.
|
53
|
+
#
|
54
|
+
def analyze
|
55
|
+
@report = HealthReport.new(source)
|
56
|
+
|
57
|
+
source.pods.each do |name|
|
58
|
+
source.versions(name).each do |version|
|
59
|
+
@pre_check_callback.call(name, version) if @pre_check_callback
|
60
|
+
spec_path = source.specification_path(name, version)
|
61
|
+
spec = lint_spec(name, version, spec_path)
|
62
|
+
check_spec_path(name, version, spec) if spec
|
63
|
+
report.analyzed_paths << spec_path
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
check_stray_specs
|
68
|
+
report
|
69
|
+
end
|
70
|
+
|
71
|
+
# @return [HealtReport] The report produced by the analysis.
|
72
|
+
#
|
73
|
+
attr_reader :report
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
# @!group Private helpers
|
78
|
+
#-----------------------------------------------------------------------#
|
79
|
+
|
80
|
+
# Checks the validity of the specification with the linter.
|
81
|
+
#
|
82
|
+
# @param [String] name
|
83
|
+
# The name of the Pod.
|
84
|
+
#
|
85
|
+
# @param [Version] version
|
86
|
+
# The version of the specification.
|
87
|
+
#
|
88
|
+
# @param [Pathname] spec_path
|
89
|
+
# The path of the specification to check.
|
90
|
+
#
|
91
|
+
# @return [Specification] The specification loaded by the linter.
|
92
|
+
# @return [Nil] If the specifications raised during evaluation.
|
93
|
+
#
|
94
|
+
def lint_spec(name, version, spec_path)
|
95
|
+
linter = Specification::Linter.new(spec_path)
|
96
|
+
linter.master_repo_mode = master_repo_mode
|
97
|
+
linter.lint
|
98
|
+
linter.results.each do |result|
|
99
|
+
type = result.type == :error ? :error : :warning
|
100
|
+
report.add_message(type, result.message, name, version)
|
101
|
+
end
|
102
|
+
linter.spec
|
103
|
+
end
|
104
|
+
|
105
|
+
# Ensures that the name and the version of the specification correspond
|
106
|
+
# to the ones expected by the repo given its path.
|
107
|
+
#
|
108
|
+
# @param [String] name
|
109
|
+
# The name of the Pod.
|
110
|
+
#
|
111
|
+
# @param [Version] version
|
112
|
+
# The version of the specification.
|
113
|
+
#
|
114
|
+
# @param [Specification] spec
|
115
|
+
# The specification to check.
|
116
|
+
#
|
117
|
+
# @return [void]
|
118
|
+
#
|
119
|
+
def check_spec_path(name, version, spec)
|
120
|
+
unless spec.name == name && spec.version == version
|
121
|
+
report.add_message(:error, "Incorrect path", name)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Checks for any stray specification in the repo.
|
126
|
+
#
|
127
|
+
# @param [Array<Pathname>] analyzed_paths
|
128
|
+
# The specification to check.
|
129
|
+
#
|
130
|
+
# @return [void]
|
131
|
+
#
|
132
|
+
def check_stray_specs
|
133
|
+
all_paths = Pathname.glob(source.repo + '**/*.podspec{,.yaml}')
|
134
|
+
stray_specs = all_paths - report.analyzed_paths
|
135
|
+
stray_specs.each do |path|
|
136
|
+
report.add_message(:error, "Stray spec", path)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
#-----------------------------------------------------------------------#
|
141
|
+
|
142
|
+
# Encapsulates the information about the state of a repo.
|
143
|
+
#
|
144
|
+
class HealthReport
|
145
|
+
|
146
|
+
# @return [Source] the source analyzed.
|
147
|
+
#
|
148
|
+
attr_reader :source
|
149
|
+
|
150
|
+
# @param [Source] @see source.
|
151
|
+
#
|
152
|
+
def initialize(source)
|
153
|
+
@source = source
|
154
|
+
@analyzed_paths = []
|
155
|
+
@pods_by_error = {}
|
156
|
+
@pods_by_warning = {}
|
157
|
+
end
|
158
|
+
|
159
|
+
# @return [Array<Pathname>] The list of the analyzed paths.
|
160
|
+
#
|
161
|
+
attr_accessor :analyzed_paths
|
162
|
+
|
163
|
+
# @return [Hash{ String => Hash }] The pods (the version grouped by
|
164
|
+
# name) grouped by an error message.
|
165
|
+
#
|
166
|
+
attr_accessor :pods_by_error
|
167
|
+
|
168
|
+
# @return [Hash{ String => Hash }] The pods (the version grouped by
|
169
|
+
# name) grouped by a warning message.
|
170
|
+
#
|
171
|
+
attr_accessor :pods_by_warning
|
172
|
+
|
173
|
+
# Adds a message with the given type for the specification with the
|
174
|
+
# given name and version.
|
175
|
+
#
|
176
|
+
# @param [Symbol] type
|
177
|
+
# The type of message. Either `:error` or `:warning`.
|
178
|
+
#
|
179
|
+
# @param [String] message
|
180
|
+
# The contents of the message.
|
181
|
+
#
|
182
|
+
# @param [String] spec_name
|
183
|
+
# The name of the Pod.
|
184
|
+
#
|
185
|
+
# @param [String] spec_version
|
186
|
+
# The version of the specification.
|
187
|
+
#
|
188
|
+
# @return [void]
|
189
|
+
#
|
190
|
+
def add_message(type, message, spec_name, spec_version = nil)
|
191
|
+
if type == :error
|
192
|
+
pods_by_error[message] ||= {}
|
193
|
+
pods_by_error[message][spec_name] ||= []
|
194
|
+
pods_by_error[message][spec_name] << spec_version
|
195
|
+
else
|
196
|
+
pods_by_warning[message] ||= {}
|
197
|
+
pods_by_warning[message][spec_name] ||= []
|
198
|
+
pods_by_warning[message][spec_name] << spec_version
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
#-----------------------------------------------------------------------#
|
204
|
+
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|