cocoapods-core 0.35.0 → 0.36.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/cocoapods-core.rb +1 -0
- data/lib/cocoapods-core/dependency.rb +3 -3
- data/lib/cocoapods-core/gem_version.rb +1 -1
- data/lib/cocoapods-core/metrics.rb +47 -0
- data/lib/cocoapods-core/platform.rb +10 -0
- data/lib/cocoapods-core/podfile.rb +7 -0
- data/lib/cocoapods-core/podfile/dsl.rb +38 -0
- data/lib/cocoapods-core/podfile/target_definition.rb +25 -0
- data/lib/cocoapods-core/specification.rb +45 -10
- data/lib/cocoapods-core/specification/consumer.rb +4 -0
- data/lib/cocoapods-core/specification/dsl.rb +19 -0
- data/lib/cocoapods-core/specification/json.rb +7 -0
- data/lib/cocoapods-core/specification/linter.rb +83 -64
- data/lib/cocoapods-core/specification/linter/analyzer.rb +13 -13
- data/lib/cocoapods-core/specification/linter/result.rb +16 -9
- data/lib/cocoapods-core/specification/set.rb +0 -1
- data/lib/cocoapods-core/specification/set/presenter.rb +11 -58
- metadata +3 -3
- data/lib/cocoapods-core/specification/set/statistics.rb +0 -263
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d1aef836bf83585db97dc487c15d8a5aa7290886
|
4
|
+
data.tar.gz: a08f076add586a3a79f71365ae02d9b63d314ca7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b8b4639f30e85fd314a5fd93c2782dc2a7d125916760b4af0db485cead247b5f09426fdf8013966cd33875549503c39dbe4d20f85b077f713636aaa5f261843e
|
7
|
+
data.tar.gz: 4fbb5d4225d96a0be864450c6b3c2112fc544b4381e0c5d3e3fcf6c1ad08d0a2296ce93462023c2ffe4f4d8549f60ff566b64de74b28cc5049049561ea25d7c2
|
data/lib/cocoapods-core.rb
CHANGED
@@ -23,6 +23,7 @@ module Pod
|
|
23
23
|
autoload :GitHub, 'cocoapods-core/github'
|
24
24
|
autoload :HTTP, 'cocoapods-core/http'
|
25
25
|
autoload :Lockfile, 'cocoapods-core/lockfile'
|
26
|
+
autoload :Metrics, 'cocoapods-core/metrics'
|
26
27
|
autoload :Platform, 'cocoapods-core/platform'
|
27
28
|
autoload :Podfile, 'cocoapods-core/podfile'
|
28
29
|
autoload :Source, 'cocoapods-core/source'
|
@@ -52,7 +52,7 @@ module Pod
|
|
52
52
|
# @example Initialization with an external source.
|
53
53
|
#
|
54
54
|
# Dependency.new('libPusher', {:git => 'example.com/repo.git'})
|
55
|
-
# Dependency.new('libPusher', {:path
|
55
|
+
# Dependency.new('libPusher', {:path => 'path/to/folder'})
|
56
56
|
# Dependency.new('libPusher', {:podspec => 'example.com/libPusher.podspec'})
|
57
57
|
#
|
58
58
|
# @overload initialize(name, is_head)
|
@@ -324,12 +324,12 @@ module Pod
|
|
324
324
|
# @return [Dependency] the dependency described by the string.
|
325
325
|
#
|
326
326
|
def self.from_string(string)
|
327
|
-
match_data = string.match(/(
|
327
|
+
match_data = string.match(/((?:\s?[^\s(])+)( (?:.*))?/)
|
328
328
|
name = match_data[1]
|
329
329
|
version = match_data[2]
|
330
330
|
version = version.gsub(/[()]/, '') if version
|
331
331
|
case version
|
332
|
-
when nil
|
332
|
+
when nil, /from `(.*)(`|')/
|
333
333
|
Dependency.new(name)
|
334
334
|
when /HEAD/
|
335
335
|
Dependency.new(name, :head)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Pod
|
2
|
+
# Allows to access metrics about pods.
|
3
|
+
#
|
4
|
+
# This class is stored in Core because it might be used by web services.
|
5
|
+
#
|
6
|
+
module Metrics
|
7
|
+
# Returns the metrics of a pod.
|
8
|
+
#
|
9
|
+
# @param [String] name
|
10
|
+
# The name of the pod.
|
11
|
+
#
|
12
|
+
# @return [Hash] The metrics for the pod.
|
13
|
+
#
|
14
|
+
def self.pod(name)
|
15
|
+
peform_request("http://metrics.cocoapods.org/api/v1/pods/#{name}")
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# @!group Private helpers
|
21
|
+
#-------------------------------------------------------------------------#
|
22
|
+
|
23
|
+
# Performs a get request with the given URL.
|
24
|
+
#
|
25
|
+
# @param [String] url
|
26
|
+
# The URL of the resource.
|
27
|
+
#
|
28
|
+
# @return [Array, Hash] The information of the resource as Ruby objects.
|
29
|
+
#
|
30
|
+
def self.peform_request(url)
|
31
|
+
require 'rest'
|
32
|
+
require 'json'
|
33
|
+
headers = { 'User-Agent' => "CocoaPods #{Pod::CORE_VERSION}" }
|
34
|
+
response = REST.get(url, headers)
|
35
|
+
body = JSON.parse(response.body)
|
36
|
+
if response.ok?
|
37
|
+
body
|
38
|
+
else
|
39
|
+
CoreUI.warn "Request to #{url} failed - #{response.status_code}"
|
40
|
+
CoreUI.warn body['message']
|
41
|
+
nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
#-------------------------------------------------------------------------#
|
46
|
+
end
|
47
|
+
end
|
@@ -166,6 +166,16 @@ module Pod
|
|
166
166
|
end
|
167
167
|
end
|
168
168
|
|
169
|
+
# @return [Bool] whether the platform supports dynamic frameworks.
|
170
|
+
#
|
171
|
+
def supports_dynamic_frameworks?
|
172
|
+
if name == :ios
|
173
|
+
deployment_target && (deployment_target >= Version.new(8.0))
|
174
|
+
else
|
175
|
+
true
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
169
179
|
# Converts the symbolic name of a platform to a string name suitable to be
|
170
180
|
# presented to the user.
|
171
181
|
#
|
@@ -101,6 +101,12 @@ module Pod
|
|
101
101
|
get_hash_value('sources') || []
|
102
102
|
end
|
103
103
|
|
104
|
+
# @return [Hash<String, Hash>] The plugins, keyed by name.
|
105
|
+
#
|
106
|
+
def plugins
|
107
|
+
get_hash_value('plugins') || {}
|
108
|
+
end
|
109
|
+
|
104
110
|
# @return [String] the path of the workspace if specified by the user.
|
105
111
|
#
|
106
112
|
def workspace_path
|
@@ -182,6 +188,7 @@ module Pod
|
|
182
188
|
sources
|
183
189
|
generate_bridge_support
|
184
190
|
set_arc_compatibility_flag
|
191
|
+
plugins
|
185
192
|
).freeze
|
186
193
|
|
187
194
|
# @return [Hash] The hash representation of the Podfile.
|
@@ -415,6 +415,16 @@ module Pod
|
|
415
415
|
current_target_definition.inhibit_all_warnings = true
|
416
416
|
end
|
417
417
|
|
418
|
+
# Use frameworks instead of static libraries for Pods.
|
419
|
+
#
|
420
|
+
# ------
|
421
|
+
#
|
422
|
+
# This attribute is inherited by child target definitions.
|
423
|
+
#
|
424
|
+
def use_frameworks!(flag = true)
|
425
|
+
current_target_definition.use_frameworks!(flag)
|
426
|
+
end
|
427
|
+
|
418
428
|
#-----------------------------------------------------------------------#
|
419
429
|
|
420
430
|
# @!group Workspace
|
@@ -525,6 +535,34 @@ module Pod
|
|
525
535
|
|
526
536
|
#-----------------------------------------------------------------------#
|
527
537
|
|
538
|
+
# Specifies the plugins that should be used during installation.
|
539
|
+
#
|
540
|
+
# -----
|
541
|
+
#
|
542
|
+
# Use this method to specify a plugin that should be used during
|
543
|
+
# installation, along with the options that should be passed to the plugin
|
544
|
+
# when it is invoked.
|
545
|
+
#
|
546
|
+
# @param [String] name
|
547
|
+
# The name of the plugin.
|
548
|
+
#
|
549
|
+
# @param [Hash] options
|
550
|
+
# The optional options that should be passed to the plugin when
|
551
|
+
# its hooks are invoked.
|
552
|
+
#
|
553
|
+
# @example Specifying to use the `slather` and `cocoapods-keys` plugins.
|
554
|
+
#
|
555
|
+
# plugin 'cocoapods-keys', keyring: 'Eidolon'
|
556
|
+
# plugin 'slather'
|
557
|
+
#
|
558
|
+
# @return [void]
|
559
|
+
#
|
560
|
+
def plugin(name, options = {})
|
561
|
+
hash_plugins = get_hash_value('plugins') || {}
|
562
|
+
(hash_plugins[name] ||= {}).merge!(options.deep_stringify_keys)
|
563
|
+
set_hash_value('plugins', hash_plugins)
|
564
|
+
end
|
565
|
+
|
528
566
|
# This hook allows you to make any changes to the Pods after they have
|
529
567
|
# been downloaded but before they are installed.
|
530
568
|
#
|
@@ -316,6 +316,30 @@ module Pod
|
|
316
316
|
|
317
317
|
#--------------------------------------#
|
318
318
|
|
319
|
+
# Sets whether the target definition should build a framework.
|
320
|
+
#
|
321
|
+
# @param [Bool] flag
|
322
|
+
# Whether a framework should be built.
|
323
|
+
#
|
324
|
+
# @return [void]
|
325
|
+
#
|
326
|
+
def use_frameworks!(flag = true)
|
327
|
+
set_hash_value('uses_frameworks', flag)
|
328
|
+
end
|
329
|
+
|
330
|
+
# @return [Bool] whether the target definition should build
|
331
|
+
# a framework.
|
332
|
+
#
|
333
|
+
def uses_frameworks?
|
334
|
+
if internal_hash['uses_frameworks'].nil?
|
335
|
+
root? ? false : parent.uses_frameworks?
|
336
|
+
else
|
337
|
+
get_hash_value('uses_frameworks')
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
#--------------------------------------#
|
342
|
+
|
319
343
|
# Whether a specific pod should be linked to the target when building for
|
320
344
|
# a specific configuration. If a pod has not been explicitly whitelisted
|
321
345
|
# for any configuration, it is implicitly whitelisted.
|
@@ -507,6 +531,7 @@ module Pod
|
|
507
531
|
dependencies
|
508
532
|
children
|
509
533
|
configuration_pod_whitelist
|
534
|
+
uses_frameworks
|
510
535
|
).freeze
|
511
536
|
|
512
537
|
# @return [Hash] The hash representation of the target definition.
|
@@ -142,6 +142,34 @@ module Pod
|
|
142
142
|
full_name.split('/').first
|
143
143
|
end
|
144
144
|
|
145
|
+
# Returns the module name of a specification
|
146
|
+
#
|
147
|
+
# @return [String] the module name
|
148
|
+
#
|
149
|
+
def module_name
|
150
|
+
attributes_hash['module_name'] ||
|
151
|
+
c99ext_identifier(attributes_hash['header_dir']) ||
|
152
|
+
c99ext_identifier(attributes_hash['name'])
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
|
157
|
+
# Transforms the given string into a valid +identifier+ after C99ext
|
158
|
+
# standard, so that it can be used in source code where escaping of
|
159
|
+
# ambiguous characters is not applicable.
|
160
|
+
#
|
161
|
+
# @param [String] name
|
162
|
+
# any name, which may contain leading numbers, spaces or invalid
|
163
|
+
# characters.
|
164
|
+
#
|
165
|
+
# @return [String]
|
166
|
+
#
|
167
|
+
def c99ext_identifier(name)
|
168
|
+
return nil if name.nil?
|
169
|
+
I18n.transliterate(name).gsub(/^([0-9])/, '_\1').
|
170
|
+
gsub(/[^a-zA-Z0-9_]/, '_').gsub(/_+/, '_')
|
171
|
+
end
|
172
|
+
|
145
173
|
#-------------------------------------------------------------------------#
|
146
174
|
|
147
175
|
public
|
@@ -204,6 +232,9 @@ module Pod
|
|
204
232
|
def subspec_by_name(relative_name, raise_if_missing = true)
|
205
233
|
if relative_name.nil? || relative_name == base_name
|
206
234
|
self
|
235
|
+
elsif relative_name.downcase == base_name.downcase
|
236
|
+
raise Informative, "Trying to access a `#{relative_name}` " \
|
237
|
+
"specification from `#{base_name}`, which has a different case."
|
207
238
|
else
|
208
239
|
remainder = relative_name[base_name.size + 1..-1]
|
209
240
|
subspec_name = remainder.split('/').shift
|
@@ -216,7 +247,7 @@ module Pod
|
|
216
247
|
return nil
|
217
248
|
end
|
218
249
|
end
|
219
|
-
subspec.subspec_by_name(remainder)
|
250
|
+
subspec.subspec_by_name(remainder, raise_if_missing)
|
220
251
|
end
|
221
252
|
end
|
222
253
|
|
@@ -506,6 +537,7 @@ module Pod
|
|
506
537
|
end
|
507
538
|
|
508
539
|
# Loads a specification with the given string.
|
540
|
+
# The specification is evaluated in the context of `path`.
|
509
541
|
#
|
510
542
|
# @param [String] spec_contents
|
511
543
|
# A string describing a specification.
|
@@ -517,16 +549,19 @@ module Pod
|
|
517
549
|
#
|
518
550
|
def self.from_string(spec_contents, path, subspec_name = nil)
|
519
551
|
path = Pathname.new(path)
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
552
|
+
spec = nil
|
553
|
+
Dir.chdir(path.parent.directory? ? path.parent : Dir.pwd) do
|
554
|
+
case path.extname
|
555
|
+
when '.podspec'
|
556
|
+
spec = ::Pod._eval_podspec(spec_contents, path)
|
557
|
+
unless spec.is_a?(Specification)
|
558
|
+
raise Informative, "Invalid podspec file at path `#{path}`."
|
559
|
+
end
|
560
|
+
when '.json'
|
561
|
+
spec = Specification.from_json(spec_contents)
|
562
|
+
else
|
563
|
+
raise Informative, "Unsupported specification format `#{path.extname}`."
|
525
564
|
end
|
526
|
-
when '.json'
|
527
|
-
spec = Specification.from_json(spec_contents)
|
528
|
-
else
|
529
|
-
raise Informative, "Unsupported specification format `#{path.extname}`."
|
530
565
|
end
|
531
566
|
|
532
567
|
spec.defined_in_file = path
|
@@ -780,6 +780,25 @@ module Pod
|
|
780
780
|
|
781
781
|
#------------------#
|
782
782
|
|
783
|
+
# @!method module_name=(name)
|
784
|
+
#
|
785
|
+
# The name to use for the framework / clang module which
|
786
|
+
# will be generated for this specification instead of the
|
787
|
+
# default (header_dir if set, otherwise the specification
|
788
|
+
# name).
|
789
|
+
#
|
790
|
+
# @example
|
791
|
+
#
|
792
|
+
# spec.module_name = 'Three20'
|
793
|
+
#
|
794
|
+
# @param [String] name
|
795
|
+
# the module name.
|
796
|
+
#
|
797
|
+
root_attribute :module_name,
|
798
|
+
:inherited => true
|
799
|
+
|
800
|
+
#------------------#
|
801
|
+
|
783
802
|
# @!method header_dir=(dir)
|
784
803
|
#
|
785
804
|
# The directory where to store the headers files so they don't break
|
@@ -8,6 +8,13 @@ module Pod
|
|
8
8
|
to_hash.to_json(*a) << "\n"
|
9
9
|
end
|
10
10
|
|
11
|
+
# @return [String] the pretty json representation of the specification.
|
12
|
+
#
|
13
|
+
def to_pretty_json(*a)
|
14
|
+
require 'json'
|
15
|
+
JSON.pretty_generate(to_hash, *a) << "\n"
|
16
|
+
end
|
17
|
+
|
11
18
|
#-----------------------------------------------------------------------#
|
12
19
|
|
13
20
|
# @return [Hash] the hash representation of the specification including
|
@@ -50,8 +50,8 @@ module Pod
|
|
50
50
|
run_root_validation_hooks
|
51
51
|
perform_all_specs_analysis
|
52
52
|
else
|
53
|
-
results.add_error "
|
54
|
-
"could not be loaded.\n\n#{@raise_message}"
|
53
|
+
results.add_error('spec', "The specification defined in `#{file}` "\
|
54
|
+
"could not be loaded.\n\n#{@raise_message}")
|
55
55
|
end
|
56
56
|
results.empty?
|
57
57
|
end
|
@@ -91,10 +91,10 @@ module Pod
|
|
91
91
|
next unless attr.required?
|
92
92
|
unless value && (!value.respond_to?(:empty?) || !value.empty?)
|
93
93
|
if attr.name == :license
|
94
|
-
results.add_warning('
|
94
|
+
results.add_warning('attributes', 'Missing required attribute' \
|
95
95
|
"`#{attr.name}`.")
|
96
96
|
else
|
97
|
-
results.add_error('
|
97
|
+
results.add_error('attributes', 'Missing required attribute' \
|
98
98
|
"`#{attr.name}`.")
|
99
99
|
end
|
100
100
|
end
|
@@ -176,28 +176,36 @@ module Pod
|
|
176
176
|
]
|
177
177
|
names_match = acceptable_names.include?(file.basename.to_s)
|
178
178
|
unless names_match
|
179
|
-
results.add_error
|
180
|
-
'name of the file.'
|
179
|
+
results.add_error('name', 'The name of the spec should match the ' \
|
180
|
+
'name of the file.')
|
181
181
|
end
|
182
182
|
|
183
183
|
if spec.root.name =~ /\s/
|
184
|
-
results.add_error
|
185
|
-
'whitespace.'
|
184
|
+
results.add_error('name', 'The name of a spec should not contain ' \
|
185
|
+
'whitespace.')
|
186
186
|
end
|
187
187
|
|
188
188
|
if spec.root.name[0, 1] == '.'
|
189
|
-
results.add_error
|
190
|
-
' with a period.'
|
189
|
+
results.add_error('name', 'The name of a spec should not begin' \
|
190
|
+
' with a period.')
|
191
191
|
end
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|
195
195
|
def _validate_version(v)
|
196
196
|
if v.to_s.empty?
|
197
|
-
results.add_error
|
197
|
+
results.add_error('version', 'A version is required.')
|
198
198
|
elsif v <= Version::ZERO
|
199
|
-
results.add_error
|
200
|
-
' higher than 0.'
|
199
|
+
results.add_error('version', 'The version of the spec should be' \
|
200
|
+
' higher than 0.')
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
# Performs validations related to the `module_name` attribute.
|
205
|
+
def _validate_module_name(m)
|
206
|
+
unless m.nil? || m =~ /^[a-z_][0-9a-z_]*$/i
|
207
|
+
results.add_error('module_name', 'The module name of a spec' \
|
208
|
+
' should be a valid C99 identifier.')
|
201
209
|
end
|
202
210
|
end
|
203
211
|
|
@@ -205,11 +213,11 @@ module Pod
|
|
205
213
|
#
|
206
214
|
def _validate_summary(s)
|
207
215
|
if s.length > 140
|
208
|
-
results.add_warning
|
209
|
-
'version of `description` (max 140 characters).'
|
216
|
+
results.add_warning('summary', 'The summary should be a short ' \
|
217
|
+
'version of `description` (max 140 characters).')
|
210
218
|
end
|
211
219
|
if s =~ /A short description of/
|
212
|
-
results.add_warning
|
220
|
+
results.add_warning('summary', 'The summary is not meaningful.')
|
213
221
|
end
|
214
222
|
end
|
215
223
|
|
@@ -217,15 +225,15 @@ module Pod
|
|
217
225
|
#
|
218
226
|
def _validate_description(d)
|
219
227
|
if d =~ /An optional longer description of/
|
220
|
-
results.add_warning
|
228
|
+
results.add_warning('description', 'The description is not meaningful.')
|
221
229
|
end
|
222
230
|
if d == spec.summary
|
223
|
-
results.add_warning
|
224
|
-
' the summary.'
|
231
|
+
results.add_warning('description', 'The description is equal to' \
|
232
|
+
' the summary.')
|
225
233
|
end
|
226
234
|
if d.length < spec.summary.length
|
227
|
-
results.add_warning
|
228
|
-
'than the summary.'
|
235
|
+
results.add_warning('description', 'The description is shorter ' \
|
236
|
+
'than the summary.')
|
229
237
|
end
|
230
238
|
end
|
231
239
|
|
@@ -233,8 +241,8 @@ module Pod
|
|
233
241
|
#
|
234
242
|
def _validate_homepage(h)
|
235
243
|
if h =~ %r{http://EXAMPLE}
|
236
|
-
results.add_warning
|
237
|
-
' from default'
|
244
|
+
results.add_warning('homepage', 'The homepage has not been updated' \
|
245
|
+
' from default')
|
238
246
|
end
|
239
247
|
end
|
240
248
|
|
@@ -242,8 +250,8 @@ module Pod
|
|
242
250
|
#
|
243
251
|
def _validate_frameworks(frameworks)
|
244
252
|
if frameworks_invalid?(frameworks)
|
245
|
-
results.add_error
|
246
|
-
' specified by its name'
|
253
|
+
results.add_error('frameworks', 'A framework should only be' \
|
254
|
+
' specified by its name')
|
247
255
|
end
|
248
256
|
end
|
249
257
|
|
@@ -251,8 +259,8 @@ module Pod
|
|
251
259
|
#
|
252
260
|
def _validate_weak_frameworks(frameworks)
|
253
261
|
if frameworks_invalid?(frameworks)
|
254
|
-
results.add_error
|
255
|
-
' specified by its name'
|
262
|
+
results.add_error('weak_frameworks', 'A weak framework should only be' \
|
263
|
+
' specified by its name')
|
256
264
|
end
|
257
265
|
end
|
258
266
|
|
@@ -262,20 +270,20 @@ module Pod
|
|
262
270
|
libs.each do |lib|
|
263
271
|
lib = lib.downcase
|
264
272
|
if lib.end_with?('.a') || lib.end_with?('.dylib')
|
265
|
-
results.add_error
|
273
|
+
results.add_error('libraries', 'Libraries should not include the' \
|
266
274
|
' extension ' \
|
267
|
-
"(`#{lib}`)"
|
275
|
+
"(`#{lib}`)")
|
268
276
|
end
|
269
277
|
|
270
278
|
if lib.start_with?('lib')
|
271
|
-
results.add_error
|
279
|
+
results.add_error('libraries', 'Libraries should omit the `lib`' \
|
272
280
|
' prefix ' \
|
273
|
-
" (`#{lib}`)"
|
281
|
+
" (`#{lib}`)")
|
274
282
|
end
|
275
283
|
|
276
284
|
if lib.include?(',')
|
277
|
-
results.add_error
|
278
|
-
"(`#{lib}`)"
|
285
|
+
results.add_error('libraries', 'Libraries should not include comas ' \
|
286
|
+
"(`#{lib}`)")
|
279
287
|
end
|
280
288
|
end
|
281
289
|
end
|
@@ -286,16 +294,16 @@ module Pod
|
|
286
294
|
type = l[:type]
|
287
295
|
file = l[:file]
|
288
296
|
if type.nil?
|
289
|
-
results.add_warning
|
297
|
+
results.add_warning('license', 'Missing license type.')
|
290
298
|
end
|
291
299
|
if type && type.gsub(' ', '').gsub("\n", '').empty?
|
292
|
-
results.add_warning
|
300
|
+
results.add_warning('license', 'Invalid license type.')
|
293
301
|
end
|
294
302
|
if type && type =~ /\(example\)/
|
295
|
-
results.add_error
|
303
|
+
results.add_error('license', 'Sample license type.')
|
296
304
|
end
|
297
305
|
if file && Pathname.new(file).extname !~ /^(\.(txt|md|markdown|))?$/i
|
298
|
-
results.add_error
|
306
|
+
results.add_error('license', 'Invalid file type')
|
299
307
|
end
|
300
308
|
end
|
301
309
|
|
@@ -307,19 +315,19 @@ module Pod
|
|
307
315
|
version = spec.version.to_s
|
308
316
|
|
309
317
|
if git =~ %r{http://EXAMPLE}
|
310
|
-
results.add_error
|
311
|
-
'example URL.'
|
318
|
+
results.add_error('source', 'The Git source still contains the ' \
|
319
|
+
'example URL.')
|
312
320
|
end
|
313
321
|
if commit && commit.downcase =~ /head/
|
314
|
-
results.add_error
|
315
|
-
' `HEAD`.'
|
322
|
+
results.add_error('source', 'The commit of a Git source cannot be' \
|
323
|
+
' `HEAD`.')
|
316
324
|
end
|
317
325
|
if tag && !tag.to_s.include?(version)
|
318
|
-
results.add_warning
|
319
|
-
' the Git tag.'
|
326
|
+
results.add_warning('source', 'The version should be included in' \
|
327
|
+
' the Git tag.')
|
320
328
|
end
|
321
329
|
if tag.nil?
|
322
|
-
results.add_warning
|
330
|
+
results.add_warning('source', 'Git sources should specify a tag.')
|
323
331
|
end
|
324
332
|
end
|
325
333
|
|
@@ -327,6 +335,15 @@ module Pod
|
|
327
335
|
check_git_ssh_source(s)
|
328
336
|
end
|
329
337
|
|
338
|
+
# Performs validations related to the `deprecated_in_favor_of` attribute.
|
339
|
+
#
|
340
|
+
def _validate_deprecated_in_favor_of(d)
|
341
|
+
if d == Specification.root_name(d)
|
342
|
+
results.add_error('deprecated_in_favor_of', 'a spec cannot be ' \
|
343
|
+
'deprecated in favor of itself')
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
330
347
|
# Performs validations related to github sources.
|
331
348
|
#
|
332
349
|
def perform_github_source_checks(s)
|
@@ -335,20 +352,22 @@ module Pod
|
|
335
352
|
if git = s[:git]
|
336
353
|
return unless git =~ /^#{URI.regexp}$/
|
337
354
|
git_uri = URI.parse(git)
|
338
|
-
if git_uri.host
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
355
|
+
perform_github_uri_checks(git, git_uri) if git_uri.host.end_with?('github.com')
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
def perform_github_uri_checks(git, git_uri)
|
360
|
+
if git_uri.host.start_with?('www.')
|
361
|
+
results.add_warning('github_sources', 'Github repositories should ' \
|
362
|
+
'not use `www` in their URL.')
|
363
|
+
end
|
364
|
+
unless git.end_with?('.git')
|
365
|
+
results.add_warning('github_sources', 'Github repositories ' \
|
366
|
+
'should end in `.git`.')
|
367
|
+
end
|
368
|
+
unless git_uri.scheme == 'https'
|
369
|
+
results.add_warning('github_sources', 'Github repositories ' \
|
370
|
+
'should use an `https` link.')
|
352
371
|
end
|
353
372
|
end
|
354
373
|
|
@@ -357,9 +376,9 @@ module Pod
|
|
357
376
|
def check_git_ssh_source(s)
|
358
377
|
if git = s[:git]
|
359
378
|
if git =~ /\w+\@(\w|\.)+\:(\/\w+)*/
|
360
|
-
results.add_warning
|
379
|
+
results.add_warning('source', 'Git SSH URLs will NOT work for ' \
|
361
380
|
'people behind firewalls configured to only allow HTTP, ' \
|
362
|
-
'therefore HTTPS is preferred.'
|
381
|
+
'therefore HTTPS is preferred.')
|
363
382
|
end
|
364
383
|
end
|
365
384
|
end
|
@@ -368,8 +387,8 @@ module Pod
|
|
368
387
|
#
|
369
388
|
def _validate_social_media_url(s)
|
370
389
|
if s =~ %r{https://twitter.com/EXAMPLE}
|
371
|
-
results.add_warning
|
372
|
-
'not been updated from the default.'
|
390
|
+
results.add_warning('social_media_url', 'The social media URL has ' \
|
391
|
+
'not been updated from the default.')
|
373
392
|
end
|
374
393
|
end
|
375
394
|
|
@@ -383,8 +402,8 @@ module Pod
|
|
383
402
|
#
|
384
403
|
def _validate_compiler_flags(flags)
|
385
404
|
if flags.join(' ').split(' ').any? { |flag| flag.start_with?('-Wno') }
|
386
|
-
results.add_warning
|
387
|
-
'(`-Wno compiler` flags).'
|
405
|
+
results.add_warning('compiler_flags', 'Warnings must not be disabled' \
|
406
|
+
'(`-Wno compiler` flags).')
|
388
407
|
end
|
389
408
|
end
|
390
409
|
|
@@ -53,7 +53,7 @@ module Pod
|
|
53
53
|
unknown_keys = keys - valid_keys
|
54
54
|
|
55
55
|
unknown_keys.each do |key|
|
56
|
-
results.add_warning "Unrecognized `#{key}` key"
|
56
|
+
results.add_warning('attributes', "Unrecognized `#{key}` key")
|
57
57
|
end
|
58
58
|
|
59
59
|
Pod::Specification::DSL.attributes.each do |_key, attribute|
|
@@ -84,8 +84,8 @@ module Pod
|
|
84
84
|
if patterns.respond_to?(:each)
|
85
85
|
patterns.each do |pattern|
|
86
86
|
if pattern.start_with?('/')
|
87
|
-
results.add_error
|
88
|
-
"relative and cannot start with a slash (#{attrb.name})."
|
87
|
+
results.add_error('File Patterns', 'File patterns must be ' \
|
88
|
+
"relative and cannot start with a slash (#{attrb.name}).")
|
89
89
|
end
|
90
90
|
end
|
91
91
|
end
|
@@ -100,10 +100,10 @@ module Pod
|
|
100
100
|
empty_patterns = methods.all? { |m| consumer.send(m).empty? }
|
101
101
|
empty = empty_patterns && consumer.spec.subspecs.empty?
|
102
102
|
if empty
|
103
|
-
results.add_error
|
103
|
+
results.add_error('File Patterns', "The #{consumer.spec} spec is " \
|
104
104
|
'empty (no source files, resources, resource_bundles, ' \
|
105
105
|
'preserve paths, vendored_libraries, vendored_frameworks, ' \
|
106
|
-
'dependencies, nor subspecs).'
|
106
|
+
'dependencies, nor subspecs).')
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
@@ -129,29 +129,29 @@ module Pod
|
|
129
129
|
def validate_attribute_array_keys(attribute, value)
|
130
130
|
unknown_keys = value.keys.map(&:to_s) - attribute.keys.map(&:to_s)
|
131
131
|
unknown_keys.each do |unknown_key|
|
132
|
-
results.add_warning "Unrecognized `#{unknown_key}` key for " \
|
133
|
-
"`#{attribute.name}` attribute."
|
132
|
+
results.add_warning('keys', "Unrecognized `#{unknown_key}` key for " \
|
133
|
+
"`#{attribute.name}` attribute.")
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
137
137
|
def validate_attribute_hash_keys(attribute, value)
|
138
138
|
major_keys = value.keys & attribute.keys.keys
|
139
139
|
if major_keys.count.zero?
|
140
|
-
results.add_warning "Missing primary key for `#{attribute.name}` " \
|
140
|
+
results.add_warning('keys', "Missing primary key for `#{attribute.name}` " \
|
141
141
|
'attribute. The acceptable ones are: ' \
|
142
|
-
"`#{attribute.keys.keys.map(&:to_s).sort.join(', ')}`."
|
142
|
+
"`#{attribute.keys.keys.map(&:to_s).sort.join(', ')}`.")
|
143
143
|
elsif major_keys.count == 1
|
144
144
|
acceptable = attribute.keys[major_keys.first] || []
|
145
145
|
unknown = value.keys - major_keys - acceptable
|
146
146
|
unless unknown.empty?
|
147
|
-
results.add_warning "Incompatible `#{unknown.sort.join(', ')}` " \
|
147
|
+
results.add_warning('keys', "Incompatible `#{unknown.sort.join(', ')}` " \
|
148
148
|
"key(s) with `#{major_keys.first}` primary key for " \
|
149
|
-
"`#{attribute.name}` attribute."
|
149
|
+
"`#{attribute.name}` attribute.")
|
150
150
|
end
|
151
151
|
else
|
152
152
|
sorted_keys = major_keys.map(&:to_s).sort
|
153
|
-
results.add_warning "Incompatible `#{sorted_keys.join(', ')}` " \
|
154
|
-
"keys for `#{attribute.name}` attribute."
|
153
|
+
results.add_warning('keys', "Incompatible `#{sorted_keys.join(', ')}` " \
|
154
|
+
"keys for `#{attribute.name}` attribute.")
|
155
155
|
end
|
156
156
|
end
|
157
157
|
end
|
@@ -9,6 +9,10 @@ module Pod
|
|
9
9
|
#
|
10
10
|
attr_reader :type
|
11
11
|
|
12
|
+
# @return[String] the name of the attribute associated with result.
|
13
|
+
#
|
14
|
+
attr_reader :attribute_name
|
15
|
+
|
12
16
|
# @return [String] the message associated with result.
|
13
17
|
#
|
14
18
|
attr_reader :message
|
@@ -16,8 +20,9 @@ module Pod
|
|
16
20
|
# @param [Symbol] type @see type
|
17
21
|
# @param [String] message @see message
|
18
22
|
#
|
19
|
-
def initialize(type, message)
|
23
|
+
def initialize(type, attribute_name, message)
|
20
24
|
@type = type
|
25
|
+
@attribute_name = attribute_name
|
21
26
|
@message = message
|
22
27
|
@platforms = []
|
23
28
|
end
|
@@ -30,7 +35,7 @@ module Pod
|
|
30
35
|
# @return [String] a string representation suitable for UI output.
|
31
36
|
#
|
32
37
|
def to_s
|
33
|
-
r = "[#{type.to_s.upcase}] #{message}"
|
38
|
+
r = "[#{type.to_s.upcase}] [#{attribute_name}] #{message}"
|
34
39
|
if platforms != Specification::PLATFORMS
|
35
40
|
platforms_names = platforms.uniq.map do |p|
|
36
41
|
Platform.string_name(p)
|
@@ -67,8 +72,8 @@ module Pod
|
|
67
72
|
#
|
68
73
|
# @return [void]
|
69
74
|
#
|
70
|
-
def add_error(message)
|
71
|
-
add_result(:error, message)
|
75
|
+
def add_error(attribute_name, message)
|
76
|
+
add_result(:error, attribute_name, message)
|
72
77
|
end
|
73
78
|
|
74
79
|
# Adds a warning result with the given message.
|
@@ -78,8 +83,8 @@ module Pod
|
|
78
83
|
#
|
79
84
|
# @return [void]
|
80
85
|
#
|
81
|
-
def add_warning(message)
|
82
|
-
add_result(:warning, message)
|
86
|
+
def add_warning(attribute_name, message)
|
87
|
+
add_result(:warning, attribute_name, message)
|
83
88
|
end
|
84
89
|
|
85
90
|
private
|
@@ -101,10 +106,12 @@ module Pod
|
|
101
106
|
#
|
102
107
|
# @return [void]
|
103
108
|
#
|
104
|
-
def add_result(type, message)
|
105
|
-
result = results.find
|
109
|
+
def add_result(type, attribute_name, message)
|
110
|
+
result = results.find do |r|
|
111
|
+
r.type == type && r.attribute_name == attribute_name && r.message == message
|
112
|
+
end
|
106
113
|
unless result
|
107
|
-
result = Result.new(type, message)
|
114
|
+
result = Result.new(type, attribute_name, message)
|
108
115
|
results << result
|
109
116
|
end
|
110
117
|
result.platforms << @consumer.platform_name if @consumer
|
@@ -11,15 +11,10 @@ module Pod
|
|
11
11
|
#
|
12
12
|
attr_reader :set
|
13
13
|
|
14
|
-
# @return [Statistics] The statistics provider.
|
15
|
-
#
|
16
|
-
attr_reader :statistics_provider
|
17
|
-
|
18
14
|
# @param [Set] set @see #set.
|
19
15
|
#
|
20
|
-
def initialize(set
|
16
|
+
def initialize(set)
|
21
17
|
@set = set
|
22
|
-
@statistics_provider = statistics_provider || Statistics.instance
|
23
18
|
end
|
24
19
|
|
25
20
|
#---------------------------------------------------------------------#
|
@@ -54,7 +49,7 @@ module Pod
|
|
54
49
|
#
|
55
50
|
# @note This method orders the sources by name.
|
56
51
|
#
|
57
|
-
def
|
52
|
+
def versions_by_source
|
58
53
|
result = []
|
59
54
|
versions_by_source = @set.versions_by_source
|
60
55
|
@set.sources.sort.each do |source|
|
@@ -179,71 +174,29 @@ module Pod
|
|
179
174
|
|
180
175
|
# @!group Statistics
|
181
176
|
|
182
|
-
# @return [Time] the creation date of the first known `podspec` of the
|
183
|
-
# Pod.
|
184
|
-
#
|
185
|
-
def creation_date
|
186
|
-
statistics_provider.creation_date(@set)
|
187
|
-
end
|
188
|
-
|
189
177
|
# @return [Integer] the GitHub likes of the repo of the Pod.
|
190
178
|
#
|
191
|
-
def
|
192
|
-
|
179
|
+
def github_stargazers
|
180
|
+
github_metrics['stargazers']
|
193
181
|
end
|
194
182
|
|
195
183
|
# @return [Integer] the GitHub forks of the repo of the Pod.
|
196
184
|
#
|
197
185
|
def github_forks
|
198
|
-
|
199
|
-
end
|
200
|
-
|
201
|
-
# @return [String] the relative time of the last push of the repo the Pod.
|
202
|
-
#
|
203
|
-
def github_last_activity
|
204
|
-
distance_from_now_in_words(statistics_provider.github_pushed_at(@set))
|
186
|
+
github_metrics['forks']
|
205
187
|
end
|
206
188
|
|
207
189
|
#---------------------------------------------------------------------#
|
208
190
|
|
209
|
-
|
191
|
+
# @!group Private Helpers
|
210
192
|
|
211
|
-
|
212
|
-
|
213
|
-
#
|
214
|
-
# @param [Time, String] from_time
|
215
|
-
# the date that should be represented.
|
216
|
-
#
|
217
|
-
# @example Possible outputs
|
218
|
-
#
|
219
|
-
# "less than a week ago"
|
220
|
-
# "15 days ago"
|
221
|
-
# "3 month ago"
|
222
|
-
# "more than a year ago"
|
223
|
-
#
|
224
|
-
# @return [String] a string that represents a past date.
|
225
|
-
#
|
226
|
-
def distance_from_now_in_words(from_time)
|
227
|
-
return nil unless from_time
|
228
|
-
from_time = Time.parse(from_time) unless from_time.is_a?(Time)
|
229
|
-
to_time = Time.now
|
230
|
-
distance_in_days = (((to_time - from_time).abs) / 60 / 60 / 24).round
|
231
|
-
|
232
|
-
case distance_in_days
|
233
|
-
when 0..7
|
234
|
-
'less than a week ago'
|
235
|
-
when 8..29
|
236
|
-
"#{distance_in_days} days ago"
|
237
|
-
when 30..45
|
238
|
-
'1 month ago'
|
239
|
-
when 46..365
|
240
|
-
"#{(distance_in_days.to_f / 30).round} months ago"
|
241
|
-
else
|
242
|
-
'more than a year ago'
|
243
|
-
end
|
193
|
+
def metrics
|
194
|
+
@metrics ||= Metrics.pod(name) || {}
|
244
195
|
end
|
245
196
|
|
246
|
-
|
197
|
+
def github_metrics
|
198
|
+
metrics['github'] || {}
|
199
|
+
end
|
247
200
|
end
|
248
201
|
end
|
249
202
|
end
|
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: 0.
|
4
|
+
version: 0.36.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: 2014-
|
12
|
+
date: 2014-12-25 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -84,6 +84,7 @@ files:
|
|
84
84
|
- lib/cocoapods-core/github.rb
|
85
85
|
- lib/cocoapods-core/http.rb
|
86
86
|
- lib/cocoapods-core/lockfile.rb
|
87
|
+
- lib/cocoapods-core/metrics.rb
|
87
88
|
- lib/cocoapods-core/platform.rb
|
88
89
|
- lib/cocoapods-core/podfile/dsl.rb
|
89
90
|
- lib/cocoapods-core/podfile/target_definition.rb
|
@@ -105,7 +106,6 @@ files:
|
|
105
106
|
- lib/cocoapods-core/specification/linter.rb
|
106
107
|
- lib/cocoapods-core/specification/root_attribute_accessors.rb
|
107
108
|
- lib/cocoapods-core/specification/set/presenter.rb
|
108
|
-
- lib/cocoapods-core/specification/set/statistics.rb
|
109
109
|
- lib/cocoapods-core/specification/set.rb
|
110
110
|
- lib/cocoapods-core/specification.rb
|
111
111
|
- lib/cocoapods-core/standard_error.rb
|
@@ -1,263 +0,0 @@
|
|
1
|
-
module Pod
|
2
|
-
class Specification
|
3
|
-
class Set
|
4
|
-
# The statistics class provides information about one or more {Set} that
|
5
|
-
# is not readily available because expensive to compute or provided by a
|
6
|
-
# remote source.
|
7
|
-
#
|
8
|
-
# The class provides also facilities to work with a collection of sets.
|
9
|
-
# It always caches in memory the computed values and it can take an
|
10
|
-
# optional path to cache file that it is responsible of populating and
|
11
|
-
# invalidating.
|
12
|
-
#
|
13
|
-
# To reuse the in memory cache and to minimize the disk access to the
|
14
|
-
# cache file a shared instance is also available.
|
15
|
-
#
|
16
|
-
class Statistics
|
17
|
-
# @return [Statistics] the shared statistics instance.
|
18
|
-
#
|
19
|
-
def self.instance
|
20
|
-
@instance ||= new
|
21
|
-
end
|
22
|
-
|
23
|
-
# Allows to set the shared instance.
|
24
|
-
#
|
25
|
-
# @param [Statistics] instance
|
26
|
-
# the new shared instance or nil.
|
27
|
-
#
|
28
|
-
# @return [Statistics] the shared statistics instance.
|
29
|
-
#
|
30
|
-
class << self
|
31
|
-
attr_writer :instance
|
32
|
-
end
|
33
|
-
|
34
|
-
# @return [Pathname] the path to the optional cache file.
|
35
|
-
#
|
36
|
-
# @note The cache file can be specified after initialization, but
|
37
|
-
# it has to be configured before requiring any value, otherwise
|
38
|
-
# it is ignored.
|
39
|
-
#
|
40
|
-
attr_accessor :cache_file
|
41
|
-
|
42
|
-
# @return [Integer] the number of seconds after which the caches of
|
43
|
-
# values that might changed are discarded.
|
44
|
-
#
|
45
|
-
# @note If not specified on initialization defaults to 3 days.
|
46
|
-
#
|
47
|
-
attr_accessor :cache_expiration
|
48
|
-
|
49
|
-
# @param [Pathname] cache_file @see cache_file
|
50
|
-
#
|
51
|
-
# @param [Integer] cache_expiration @see cache_expiration
|
52
|
-
#
|
53
|
-
def initialize(cache_file = nil, cache_expiration = (60 * 60 * 24 * 3))
|
54
|
-
require 'yaml'
|
55
|
-
|
56
|
-
@cache_file = cache_file
|
57
|
-
@cache_expiration = cache_expiration
|
58
|
-
end
|
59
|
-
|
60
|
-
#---------------------------------------------------------------------#
|
61
|
-
|
62
|
-
# @!group Accessing the statistics
|
63
|
-
|
64
|
-
# Computes the date in which the first podspec of a set was committed
|
65
|
-
# on its git source.
|
66
|
-
#
|
67
|
-
# @param [Set] set
|
68
|
-
# the set for the Pod whose creation date is needed.
|
69
|
-
#
|
70
|
-
# @note The set should be generated with only the source that is
|
71
|
-
# analyzed. If there are more than one the first one is
|
72
|
-
# processed.
|
73
|
-
#
|
74
|
-
# @note This method needs to traverse the git history of the repo and
|
75
|
-
# thus incurs in a performance hit.
|
76
|
-
#
|
77
|
-
# @return [Time] the date in which a Pod appeared for the first time on
|
78
|
-
# the {Source}.
|
79
|
-
#
|
80
|
-
def creation_date(set)
|
81
|
-
date = compute_creation_date(set)
|
82
|
-
save_cache
|
83
|
-
date
|
84
|
-
end
|
85
|
-
|
86
|
-
# Computes the date in which the first podspec of each given set was
|
87
|
-
# committed on its git source.
|
88
|
-
#
|
89
|
-
# @param [Array<Set>] sets
|
90
|
-
# the list of the sets for the Pods whose creation date is
|
91
|
-
# needed.
|
92
|
-
#
|
93
|
-
# @note @see creation_date
|
94
|
-
#
|
95
|
-
# @note This method is optimized for multiple sets because it saves
|
96
|
-
# the cache file only once.
|
97
|
-
#
|
98
|
-
# @return [Array<Time>] the list of the dates in which the Pods
|
99
|
-
# appeared for the first time on the {Source}.
|
100
|
-
#
|
101
|
-
def creation_dates(sets)
|
102
|
-
dates = {}
|
103
|
-
sets.each { |set| dates[set.name] = compute_creation_date(set) }
|
104
|
-
save_cache
|
105
|
-
dates
|
106
|
-
end
|
107
|
-
|
108
|
-
# Computes the number of likes that a Pod has on Github.
|
109
|
-
#
|
110
|
-
# @param [Set] set
|
111
|
-
# the set of the Pod.
|
112
|
-
#
|
113
|
-
# @return [Integer] the number of likes or nil if the Pod is not hosted
|
114
|
-
# on GitHub.
|
115
|
-
#
|
116
|
-
def github_watchers(set)
|
117
|
-
github_stats_if_needed(set)
|
118
|
-
get_value(set, :gh_watchers)
|
119
|
-
end
|
120
|
-
|
121
|
-
# Computes the number of forks that a Pod has on Github.
|
122
|
-
#
|
123
|
-
# @param [Set] set @see github_watchers
|
124
|
-
#
|
125
|
-
# @return [Integer] the number of forks or nil if the Pod is not hosted
|
126
|
-
# on GitHub.
|
127
|
-
#
|
128
|
-
def github_forks(set)
|
129
|
-
github_stats_if_needed(set)
|
130
|
-
get_value(set, :gh_forks)
|
131
|
-
end
|
132
|
-
|
133
|
-
# Computes the number of likes that a Pod has on Github.
|
134
|
-
#
|
135
|
-
# @param [Set] set @see github_watchers
|
136
|
-
#
|
137
|
-
# @return [Time] the time of the last push or nil if the Pod is not
|
138
|
-
# hosted on GitHub.
|
139
|
-
#
|
140
|
-
def github_pushed_at(set)
|
141
|
-
github_stats_if_needed(set)
|
142
|
-
string_time = get_value(set, :pushed_at)
|
143
|
-
Time.parse(string_time) if string_time
|
144
|
-
end
|
145
|
-
|
146
|
-
#---------------------------------------------------------------------#
|
147
|
-
|
148
|
-
private
|
149
|
-
|
150
|
-
# @return [Hash{String => Hash}] the in-memory cache, where for each
|
151
|
-
# set is stored a hash with the result of the computations.
|
152
|
-
#
|
153
|
-
def cache
|
154
|
-
unless @cache
|
155
|
-
if cache_file && cache_file.exist?
|
156
|
-
@cache = YAMLHelper.load_string(cache_file.read)
|
157
|
-
else
|
158
|
-
@cache = {}
|
159
|
-
end
|
160
|
-
end
|
161
|
-
@cache
|
162
|
-
end
|
163
|
-
|
164
|
-
# Returns the value for the given key of a set stored in the cache, if
|
165
|
-
# available.
|
166
|
-
#
|
167
|
-
# @param [Set] set
|
168
|
-
# the set for which the value is needed.
|
169
|
-
#
|
170
|
-
# @param [Symbol] key
|
171
|
-
# the key of the value.
|
172
|
-
#
|
173
|
-
# @return [Object] the value or nil.
|
174
|
-
#
|
175
|
-
def get_value(set, key)
|
176
|
-
if cache[set.name] && cache[set.name][key]
|
177
|
-
cache[set.name][key]
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
# Stores the given value of a set for the given key in the cache.
|
182
|
-
#
|
183
|
-
# @param [Set] set
|
184
|
-
# the set for which the value has to be stored.
|
185
|
-
#
|
186
|
-
# @param [Symbol] key
|
187
|
-
# the key of the value.
|
188
|
-
#
|
189
|
-
# @param [Object] value
|
190
|
-
# the value to store.
|
191
|
-
#
|
192
|
-
# @return [Object] the value or nil.
|
193
|
-
#
|
194
|
-
def set_value(set, key, value)
|
195
|
-
cache[set.name] ||= {}
|
196
|
-
cache[set.name][key] = value
|
197
|
-
end
|
198
|
-
|
199
|
-
# Saves the in-memory cache to the path of cache file if specified.
|
200
|
-
#
|
201
|
-
# @return [void]
|
202
|
-
#
|
203
|
-
def save_cache
|
204
|
-
if cache_file
|
205
|
-
yaml = YAML.dump(cache)
|
206
|
-
File.open(cache_file, 'w') { |f| f.write(yaml) }
|
207
|
-
end
|
208
|
-
end
|
209
|
-
|
210
|
-
# Analyzes the history of the git repository of the {Source} of the
|
211
|
-
# given {Set} to find when its folder was created.
|
212
|
-
#
|
213
|
-
# @param [Set] set
|
214
|
-
# the set for which the creation date is needed.
|
215
|
-
#
|
216
|
-
# @return [Time] the date in which a Pod was created.
|
217
|
-
#
|
218
|
-
def compute_creation_date(set)
|
219
|
-
date = get_value(set, :creation_date)
|
220
|
-
unless date
|
221
|
-
Dir.chdir(set.sources.first.repo) do
|
222
|
-
git_log = `git log --first-parent --format=%ct "#{set.name}"`
|
223
|
-
creation_date = git_log.split("\n").last.to_i
|
224
|
-
date = Time.at(creation_date)
|
225
|
-
end
|
226
|
-
set_value(set, :creation_date, date)
|
227
|
-
end
|
228
|
-
date
|
229
|
-
end
|
230
|
-
|
231
|
-
# Retrieved the GitHub information from the API for the given set and
|
232
|
-
# stores it in the in-memory cache.
|
233
|
-
#
|
234
|
-
# @note If there is a valid cache and it was generated withing the
|
235
|
-
# expiration time frame this method does nothing.
|
236
|
-
#
|
237
|
-
# @param [Set] set
|
238
|
-
# the set for which the GitHub information is needed.
|
239
|
-
#
|
240
|
-
# @return [void]
|
241
|
-
#
|
242
|
-
def github_stats_if_needed(set)
|
243
|
-
update_date = get_value(set, :gh_date)
|
244
|
-
return if update_date && update_date > (Time.now - cache_expiration)
|
245
|
-
|
246
|
-
spec = set.specification
|
247
|
-
url = spec.source[:git]
|
248
|
-
repo = GitHub.repo(url) if url
|
249
|
-
|
250
|
-
if repo
|
251
|
-
set_value(set, :gh_watchers, repo['watchers'])
|
252
|
-
set_value(set, :gh_forks, repo['forks'])
|
253
|
-
set_value(set, :pushed_at, repo['pushed_at'])
|
254
|
-
set_value(set, :gh_date, Time.now)
|
255
|
-
save_cache
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
#---------------------------------------------------------------------#
|
260
|
-
end
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|