cocoapods-core 0.35.0 → 0.36.0.beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|