cdnget 0.1.0
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 +7 -0
- data/MIT-LICENSE +21 -0
- data/README.md +45 -0
- data/Rakefile +144 -0
- data/bin/cdnget +530 -0
- data/cdnget.gemspec +28 -0
- data/lib/cdnget.rb +530 -0
- data/test/cdnget_test.rb +471 -0
- metadata +80 -0
data/cdnget.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |o|
|
4
|
+
o.name = "cdnget"
|
5
|
+
o.version = '$Release: 0.1.0 $'.split()[1]
|
6
|
+
o.authors = ["makoto kuwata"]
|
7
|
+
o.email = ["kwa@kuwata-lab.com"]
|
8
|
+
|
9
|
+
o.summary = "Utility to download files from CDNJS, jsDelivr or Google."
|
10
|
+
o.description = "Utility to download files from CDNJS, jsDelivr or Google."
|
11
|
+
o.homepage = "https://github.com/kwatch/cdnget"
|
12
|
+
o.license = "MIT"
|
13
|
+
|
14
|
+
o.files = Dir[*%w[
|
15
|
+
README.md MIT-LICENSE Rakefile cdnget.gemspec
|
16
|
+
lib/**/*.rb
|
17
|
+
bin/cdnget
|
18
|
+
test/**/*_test.rb
|
19
|
+
]]
|
20
|
+
o.bindir = "bin"
|
21
|
+
o.executables = ["cdnget"]
|
22
|
+
o.require_paths = ["lib"]
|
23
|
+
|
24
|
+
o.required_ruby_version = '>= 2.0'
|
25
|
+
|
26
|
+
o.add_development_dependency "minitest", "~> 5.4"
|
27
|
+
o.add_development_dependency "minitest-ok", "~> 1.0"
|
28
|
+
end
|
data/lib/cdnget.rb
ADDED
@@ -0,0 +1,530 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
##
|
5
|
+
## Download files from CDN (CDNJS, Google, jsDelivr).
|
6
|
+
##
|
7
|
+
## - CDNJS (https://cdnjs.com/)
|
8
|
+
## - Google (https://developers.google.com/speed/libraries/)
|
9
|
+
## - jsDelivr (https://www.jsdelivr.com/)
|
10
|
+
##
|
11
|
+
## Example:
|
12
|
+
## $ cdnget # list public CDN
|
13
|
+
## $ cdnget [-q] cdnjs # list libraries
|
14
|
+
## $ cdnget [-q] cdnjs jquery # list versions
|
15
|
+
## $ cdnget [-q] cdnjs jquery 2.2.0 # list files
|
16
|
+
## $ cdnget [-q] cdnjs jquery 2.2.0 /tmp # download files
|
17
|
+
##
|
18
|
+
|
19
|
+
require 'open-uri'
|
20
|
+
require 'json'
|
21
|
+
require 'fileutils'
|
22
|
+
|
23
|
+
|
24
|
+
module CDNGet
|
25
|
+
|
26
|
+
|
27
|
+
RELEASE = '$Release: 0.1.0 $'.split()[1]
|
28
|
+
|
29
|
+
CLASSES = []
|
30
|
+
|
31
|
+
|
32
|
+
class Base
|
33
|
+
|
34
|
+
def self.inherited(klass)
|
35
|
+
CLASSES << klass
|
36
|
+
end
|
37
|
+
|
38
|
+
def list()
|
39
|
+
raise NotImplementedError.new("#{self.class.name}#list(): not implemented yet.")
|
40
|
+
end
|
41
|
+
|
42
|
+
def find(library)
|
43
|
+
raise NotImplementedError.new("#{self.class.name}#find(): not implemented yet.")
|
44
|
+
end
|
45
|
+
|
46
|
+
def get(library, version)
|
47
|
+
raise NotImplementedError.new("#{self.class.name}#get(): not implemented yet.")
|
48
|
+
end
|
49
|
+
|
50
|
+
def download(library, version, basedir=".", quiet: false)
|
51
|
+
validate(library, version)
|
52
|
+
File.exist?(basedir) or
|
53
|
+
raise CommandError.new("#{basedir}: not exist.")
|
54
|
+
File.directory?(basedir) or
|
55
|
+
raise CommandError.new("#{basedir}: not a directory.")
|
56
|
+
target_dir = File.join(basedir, library, version)
|
57
|
+
d = get(library, version)
|
58
|
+
d[:files].each do |file|
|
59
|
+
filepath = File.join(target_dir, file)
|
60
|
+
dirpath = File.dirname(filepath)
|
61
|
+
print "#{filepath} ..." unless quiet
|
62
|
+
url = File.join(d[:baseurl], file) # not use URI.join!
|
63
|
+
content = fetch(url)
|
64
|
+
content = content.force_encoding('ascii-8bit')
|
65
|
+
print " Done (#{format_integer(content.bytesize)} byte)" unless quiet
|
66
|
+
FileUtils.mkdir_p(dirpath) unless File.exist?(dirpath)
|
67
|
+
unchanged = File.exist?(filepath) && File.read(filepath, mode: 'rb') == content
|
68
|
+
if unchanged
|
69
|
+
print " (Unchanged)" unless quiet
|
70
|
+
else
|
71
|
+
File.open(filepath, 'wb') {|f| f.write(content) }
|
72
|
+
end
|
73
|
+
puts() unless quiet
|
74
|
+
end
|
75
|
+
nil
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
def fetch(url, library=nil)
|
81
|
+
begin
|
82
|
+
html = open(url, 'rb') {|f| f.read() }
|
83
|
+
return html
|
84
|
+
rescue OpenURI::HTTPError => ex
|
85
|
+
raise CommandError.new("GET #{url} : #{ex.message}")
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def validate(library, version)
|
90
|
+
if library
|
91
|
+
library =~ /\A[-.\w]+\z/ or
|
92
|
+
raise ArgumentError.new("#{library.inspect}: Unexpected library name.")
|
93
|
+
end
|
94
|
+
if version
|
95
|
+
version =~ /\A\d+(\.\d+)+([-.\w]+)?/ or
|
96
|
+
raise ArgumentError.new("#{version.inspect}: Unexpected version number.")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def format_integer(value)
|
101
|
+
return value.to_s.reverse.scan(/..?.?/).collect {|s| s.reverse }.reverse.join(',')
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
class HttpError < StandardError
|
108
|
+
end
|
109
|
+
|
110
|
+
|
111
|
+
class CDNJS < Base # TODO: use jsdelivr api
|
112
|
+
CODE = "cdnjs"
|
113
|
+
SITE_URL = 'https://cdnjs.com/'
|
114
|
+
|
115
|
+
def fetch(url, library=nil)
|
116
|
+
begin
|
117
|
+
html = open(url, 'rb') {|f| f.read() }
|
118
|
+
if library
|
119
|
+
html =~ /<h1\b.*?>(.*?)<\/h1>/ or
|
120
|
+
raise CommandError.new("#{library}: Library not found.")
|
121
|
+
library == $1.strip() or
|
122
|
+
raise CommandError.new("#{library}: Library not found (maybe '#{$1.strip()}'?).")
|
123
|
+
end
|
124
|
+
return html
|
125
|
+
rescue OpenURI::HTTPError => ex
|
126
|
+
raise HttpError.new("GET #{url} : #{ex.message}")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
protected :fetch
|
130
|
+
|
131
|
+
def list
|
132
|
+
libs = []
|
133
|
+
html = fetch("https://cdnjs.com/libraries")
|
134
|
+
html.scan(/<td\b(.*?)<\/td>/m) do |str,|
|
135
|
+
name = desc = nil
|
136
|
+
name = $1 if str =~ /href="\/libraries\/([-.\w]+)">\s*\1\s*<\/a>/
|
137
|
+
desc = $1.strip if str =~ /<div style="display: none;">(.*?)<\/div>/m
|
138
|
+
libs << {name: name, desc: desc} if name
|
139
|
+
end
|
140
|
+
return libs.sort_by {|d| d[:name] }.uniq
|
141
|
+
end
|
142
|
+
|
143
|
+
def find(library)
|
144
|
+
validate(library, nil)
|
145
|
+
html = fetch("https://cdnjs.com/libraries/#{library}", library)
|
146
|
+
versions = []
|
147
|
+
html.scan(/<option value="([^"]+)" *(?:selected)?>/) do |ver,|
|
148
|
+
versions << ver
|
149
|
+
end
|
150
|
+
desc = tags = nil
|
151
|
+
if html =~ /<p>(.*?)<\/p>\s*<em>(.*?)<\/em>/
|
152
|
+
desc = $1
|
153
|
+
tags = $2
|
154
|
+
end
|
155
|
+
return {
|
156
|
+
name: library,
|
157
|
+
desc: desc,
|
158
|
+
tags: tags,
|
159
|
+
versions: versions,
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
def get(library, version)
|
164
|
+
validate(library, version)
|
165
|
+
html = fetch("https://cdnjs.com/libraries/#{library}/#{version}", library)
|
166
|
+
baseurl = "https://cdnjs.cloudflare.com/ajax/libs/#{library}/#{version}"
|
167
|
+
urls = []
|
168
|
+
files = []
|
169
|
+
rexp = %r`>(#{Regexp.escape(baseurl)}/([^<]+))<\/p>`
|
170
|
+
html.scan(%r`>(#{Regexp.escape(baseurl)}/([^<]+))<\/p>`) do |url, file|
|
171
|
+
urls << url .gsub(///, '/')
|
172
|
+
files << file.gsub(///, '/')
|
173
|
+
end
|
174
|
+
return {
|
175
|
+
name: library,
|
176
|
+
version: version,
|
177
|
+
urls: urls,
|
178
|
+
files: files,
|
179
|
+
baseurl: baseurl,
|
180
|
+
}
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
|
186
|
+
class JSDelivr < Base
|
187
|
+
CODE = "jsdelivr"
|
188
|
+
SITE_URL = "https://www.jsdelivr.com/"
|
189
|
+
API_URL = "https://api.jsdelivr.com/v1/jsdelivr/libraries"
|
190
|
+
|
191
|
+
def list
|
192
|
+
json = fetch("#{API_URL}?fields=name,description,homepage")
|
193
|
+
arr = JSON.load(json)
|
194
|
+
return arr.collect {|d|
|
195
|
+
{name: d["name"], desc: d["description"], site: d["homepage"] }
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
def find(library)
|
200
|
+
validate(library, nil)
|
201
|
+
json = fetch("#{API_URL}?name=#{library}&fields=name,description,homepage,versions")
|
202
|
+
arr = JSON.load(json)
|
203
|
+
d = arr.first or
|
204
|
+
raise CommandError.new("#{library}: Library not found.")
|
205
|
+
return {
|
206
|
+
name: d['name'],
|
207
|
+
desc: d['description'],
|
208
|
+
site: d['homepage'],
|
209
|
+
versions: d['versions'],
|
210
|
+
}
|
211
|
+
end
|
212
|
+
|
213
|
+
def get(library, version)
|
214
|
+
validate(library, version)
|
215
|
+
baseurl = "https://cdn.jsdelivr.net/#{library}/#{version}"
|
216
|
+
url = "#{API_URL}/#{library}/#{version}"
|
217
|
+
json = fetch("#{API_URL}/#{library}/#{version}")
|
218
|
+
files = JSON.load(json)
|
219
|
+
! files.empty? or
|
220
|
+
raise CommandError.new("#{library}: Library not found.")
|
221
|
+
urls = files.collect {|x| "#{baseurl}/#{x}" }
|
222
|
+
return {
|
223
|
+
name: library,
|
224
|
+
version: version,
|
225
|
+
urls: urls,
|
226
|
+
files: files,
|
227
|
+
baseurl: baseurl,
|
228
|
+
}
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
|
233
|
+
|
234
|
+
class GoogleCDN < Base # TODO: use jsdelivr api
|
235
|
+
CODE = "google"
|
236
|
+
SITE_URL = 'https://developers.google.com/speed/libraries/'
|
237
|
+
|
238
|
+
def list
|
239
|
+
libs = []
|
240
|
+
html = fetch("https://developers.google.com/speed/libraries/")
|
241
|
+
rexp = %r`"https://ajax\.googleapis\.com/ajax/libs/([^/]+)/([^/]+)/([^"]+)"`
|
242
|
+
html.scan(rexp) do |lib, ver, file|
|
243
|
+
libs << {name: lib, desc: "latest version: #{ver}" }
|
244
|
+
end
|
245
|
+
return libs.sort_by {|d| d[:name] }.uniq
|
246
|
+
end
|
247
|
+
|
248
|
+
def find(library)
|
249
|
+
validate(library, nil)
|
250
|
+
html = fetch("https://developers.google.com/speed/libraries/")
|
251
|
+
rexp = %r`"https://ajax\.googleapis\.com/ajax/libs/#{library}/`
|
252
|
+
site_url = nil
|
253
|
+
versions = []
|
254
|
+
urls = []
|
255
|
+
found = false
|
256
|
+
html.scan(/<h3\b.*?>.*?<\/h3>\s*<dl>(.*?)<\/dl>/m) do |text,|
|
257
|
+
if text =~ rexp
|
258
|
+
found = true
|
259
|
+
if text =~ /<dt>.*?snippet:<\/dt>\s*<dd>(.*?)<\/dd>/m
|
260
|
+
s = $1
|
261
|
+
s.scan(/\b(?:src|href)="([^"]*?)"/) do |href,|
|
262
|
+
urls << href
|
263
|
+
end
|
264
|
+
end
|
265
|
+
if text =~ /<dt>site:<\/dt>\s*<dd>(.*?)<\/dd>/m
|
266
|
+
s = $1
|
267
|
+
if s =~ %r`href="([^"]+)"`
|
268
|
+
site_url = $1
|
269
|
+
end
|
270
|
+
end
|
271
|
+
text.scan(/<dt>(?:stable |unstable )?versions:<\/dt>\s*<dd\b.*?>(.*?)<\/dd>/m) do
|
272
|
+
s = $1
|
273
|
+
vers = s.split(/,/).collect {|x| x.strip() }
|
274
|
+
versions.concat(vers)
|
275
|
+
end
|
276
|
+
break
|
277
|
+
end
|
278
|
+
end
|
279
|
+
found or
|
280
|
+
raise CommandError.new("#{library}: Library not found.")
|
281
|
+
return {
|
282
|
+
name: library,
|
283
|
+
site: site_url,
|
284
|
+
urls: urls,
|
285
|
+
versions: versions,
|
286
|
+
}
|
287
|
+
end
|
288
|
+
|
289
|
+
def get(library, version)
|
290
|
+
validate(library, version)
|
291
|
+
d = find(library)
|
292
|
+
d[:versions].find(version) or
|
293
|
+
raise CommandError.new("#{version}: No such version of #{library}.")
|
294
|
+
urls = d[:urls]
|
295
|
+
if urls
|
296
|
+
rexp = /(\/libs\/#{library})\/[^\/]+/
|
297
|
+
urls = urls.collect {|x| x.gsub(rexp, "\\1/#{version}") }
|
298
|
+
end
|
299
|
+
baseurl = "https://ajax.googleapis.com/ajax/libs/#{library}/#{version}"
|
300
|
+
files = urls ? urls.collect {|x| x[baseurl.length..-1] } : nil
|
301
|
+
return {
|
302
|
+
name: d[:name],
|
303
|
+
site: d[:site],
|
304
|
+
urls: urls,
|
305
|
+
files: files,
|
306
|
+
baseurl: baseurl,
|
307
|
+
version: version,
|
308
|
+
}
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
|
314
|
+
#class JQueryCDN < Base
|
315
|
+
# CODE = "jquery"
|
316
|
+
# SITE_URL = 'https://code.jquery.com/'
|
317
|
+
#end
|
318
|
+
|
319
|
+
|
320
|
+
#class ASPNetCDN < Base
|
321
|
+
# CODE = "aspnet"
|
322
|
+
# SITE_URL = 'https://www.asp.net/ajax/cdn/'
|
323
|
+
#end
|
324
|
+
|
325
|
+
|
326
|
+
class CommandError < StandardError
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
class Main
|
331
|
+
|
332
|
+
def initialize(script=nil)
|
333
|
+
@script = script || File.basename($0)
|
334
|
+
end
|
335
|
+
|
336
|
+
def help_message
|
337
|
+
script = @script
|
338
|
+
return <<END
|
339
|
+
#{script} -- download files from public CDN
|
340
|
+
|
341
|
+
Usage: #{script} [options] [CDN] [library] [version] [directory]
|
342
|
+
|
343
|
+
Options:
|
344
|
+
-h, --help : help
|
345
|
+
-v, --version : version
|
346
|
+
-q, --quiet : minimal output
|
347
|
+
|
348
|
+
Example:
|
349
|
+
$ #{script} # list public CDN
|
350
|
+
$ #{script} [-q] cdnjs # list libraries
|
351
|
+
$ #{script} [-q] cdnjs jquery # list versions
|
352
|
+
$ #{script} [-q] cdnjs jquery 2.2.0 # list files
|
353
|
+
$ #{script} [-q] cdnjs jquery 2.2.0 /tmp # download files
|
354
|
+
END
|
355
|
+
end
|
356
|
+
|
357
|
+
def self.main(args=nil)
|
358
|
+
args ||= ARGV
|
359
|
+
s = self.new().run(*args)
|
360
|
+
puts s if s
|
361
|
+
exit 0
|
362
|
+
rescue CommandError => ex
|
363
|
+
$stderr.puts ex.message
|
364
|
+
exit 1
|
365
|
+
end
|
366
|
+
|
367
|
+
def run(*args)
|
368
|
+
cmdopts = parse_cmdopts(args, "hvq", ["help", "version", "quiet"])
|
369
|
+
return help_message() if cmdopts['h'] || cmdopts['help']
|
370
|
+
return RELEASE + "\n" if cmdopts['v'] || cmdopts['version']
|
371
|
+
@quiet = cmdopts['quiet'] || cmdopts['q']
|
372
|
+
#
|
373
|
+
validate(args[1], args[2])
|
374
|
+
#
|
375
|
+
case args.length
|
376
|
+
when 0
|
377
|
+
return do_list_cdns()
|
378
|
+
when 1
|
379
|
+
cdn_code = args[0]
|
380
|
+
return do_list_libraries(cdn_code)
|
381
|
+
when 2
|
382
|
+
cdn_code, library = args
|
383
|
+
if library.include?('*')
|
384
|
+
return do_search_libraries(cdn_code, library)
|
385
|
+
else
|
386
|
+
return do_find_library(cdn_code, library)
|
387
|
+
end
|
388
|
+
when 3
|
389
|
+
cdn_code, library, version = args
|
390
|
+
return do_get_library(cdn_code, library, version)
|
391
|
+
when 4
|
392
|
+
cdn_code, library, version, basedir = args
|
393
|
+
do_download_library(cdn_code, library, version, basedir)
|
394
|
+
return ""
|
395
|
+
else
|
396
|
+
raise CommandError.new("'#{args[4]}': Too many arguments.")
|
397
|
+
end
|
398
|
+
end
|
399
|
+
|
400
|
+
def validate(library, version)
|
401
|
+
if library && ! library.include?('*')
|
402
|
+
library =~ /\A[-.\w]+\z/ or
|
403
|
+
raise CommandError.new("#{library}: Unexpected library name.")
|
404
|
+
end
|
405
|
+
if version
|
406
|
+
version =~ /\A[-.\w]+\z/ or
|
407
|
+
raise CommandError.new("#{version}: Unexpected version number.")
|
408
|
+
end
|
409
|
+
end
|
410
|
+
|
411
|
+
def parse_cmdopts(cmdargs, short_opts, long_opts)
|
412
|
+
cmdopts = {}
|
413
|
+
while cmdargs[0] && cmdargs[0].start_with?('-')
|
414
|
+
cmdarg = cmdargs.shift
|
415
|
+
if cmdarg == '--'
|
416
|
+
break
|
417
|
+
elsif cmdarg.start_with?('--')
|
418
|
+
cmdarg =~ /\A--(\w[-\w]+)(=.*?)?/ or
|
419
|
+
raise CommandError.new("#{cmdarg}: invalid command option.")
|
420
|
+
name = $1
|
421
|
+
value = $2 ? $2[1..-1] : true
|
422
|
+
long_opts.include?(name) or
|
423
|
+
raise CommandError.new("#{cmdarg}: unknown command option.")
|
424
|
+
cmdopts[name] = value
|
425
|
+
elsif cmdarg.start_with?('-')
|
426
|
+
cmdarg[1..-1].each_char do |c|
|
427
|
+
short_opts.include?(c) or
|
428
|
+
raise CommandError.new("-#{c}: unknown command option.")
|
429
|
+
cmdopts[c] = true
|
430
|
+
end
|
431
|
+
else
|
432
|
+
raise "unreachable"
|
433
|
+
end
|
434
|
+
end
|
435
|
+
return cmdopts
|
436
|
+
end
|
437
|
+
|
438
|
+
def find_cdn(cdn_code)
|
439
|
+
klass = CLASSES.find {|c| c::CODE == cdn_code } or
|
440
|
+
raise CommandError.new("#{cdn_code}: no such CDN.")
|
441
|
+
return klass.new
|
442
|
+
end
|
443
|
+
|
444
|
+
def render_list(list)
|
445
|
+
if @quiet
|
446
|
+
return list.collect {|d| "#{d[:name]}\n" }.join()
|
447
|
+
else
|
448
|
+
return list.collect {|d| "%-20s # %s\n" % [d[:name], d[:desc]] }.join()
|
449
|
+
end
|
450
|
+
end
|
451
|
+
|
452
|
+
def do_list_cdns
|
453
|
+
if @quiet
|
454
|
+
return CLASSES.map {|c| "#{c::CODE}\n" }.join()
|
455
|
+
else
|
456
|
+
return CLASSES.map {|c| "%-10s # %s\n" % [c::CODE, c::SITE_URL] }.join()
|
457
|
+
end
|
458
|
+
end
|
459
|
+
|
460
|
+
def do_list_libraries(cdn_code)
|
461
|
+
cdn = find_cdn(cdn_code)
|
462
|
+
return render_list(cdn.list)
|
463
|
+
end
|
464
|
+
|
465
|
+
def do_search_libraries(cdn_code, pattern)
|
466
|
+
cdn = find_cdn(cdn_code)
|
467
|
+
rexp_str = pattern.split('*', -1).collect {|x| Regexp.escape(x) }.join('.*')
|
468
|
+
rexp = Regexp.compile("\\A#{rexp_str}\\z", Regexp::IGNORECASE)
|
469
|
+
return render_list(cdn.list.select {|a| a[:name] =~ rexp })
|
470
|
+
end
|
471
|
+
|
472
|
+
def do_find_library(cdn_code, library)
|
473
|
+
cdn = find_cdn(cdn_code)
|
474
|
+
d = cdn.find(library)
|
475
|
+
s = ""
|
476
|
+
if @quiet
|
477
|
+
d[:versions].each do |ver|
|
478
|
+
s << "#{ver}\n"
|
479
|
+
end if d[:versions]
|
480
|
+
else
|
481
|
+
s << "name: #{d[:name]}\n"
|
482
|
+
s << "desc: #{d[:desc]}\n" if d[:desc]
|
483
|
+
s << "tags: #{d[:tags]}\n" if d[:tags]
|
484
|
+
s << "site: #{d[:site]}\n" if d[:site]
|
485
|
+
s << "snippet: |\n" << d[:snippet].gsub(/^/, ' ') if d[:snippet]
|
486
|
+
s << "versions:\n"
|
487
|
+
d[:versions].each do |ver|
|
488
|
+
s << " - #{ver}\n"
|
489
|
+
end if d[:versions]
|
490
|
+
end
|
491
|
+
return s
|
492
|
+
end
|
493
|
+
|
494
|
+
def do_get_library(cdn_code, library, version)
|
495
|
+
cdn = find_cdn(cdn_code)
|
496
|
+
d = cdn.get(library, version)
|
497
|
+
s = ""
|
498
|
+
if @quiet
|
499
|
+
d[:urls].each do |url|
|
500
|
+
s << "#{url}\n"
|
501
|
+
end if d[:urls]
|
502
|
+
else
|
503
|
+
s << "name: #{d[:name]}\n"
|
504
|
+
s << "version: #{d[:version]}\n"
|
505
|
+
s << "tags: #{d[:tags]}\n" if d[:tags]
|
506
|
+
s << "site: #{d[:site]}\n" if d[:site]
|
507
|
+
s << "snippet: |\n" << d[:snippet].gsub(/^/, ' ') if d[:snippet]
|
508
|
+
s << "urls:\n" if d[:urls]
|
509
|
+
d[:urls].each do |url|
|
510
|
+
s << " - #{url}\n"
|
511
|
+
end if d[:urls]
|
512
|
+
end
|
513
|
+
return s
|
514
|
+
end
|
515
|
+
|
516
|
+
def do_download_library(cdn_code, library, version, basedir)
|
517
|
+
cdn = find_cdn(cdn_code)
|
518
|
+
cdn.download(library, version, basedir, quiet: @quiet)
|
519
|
+
return nil
|
520
|
+
end
|
521
|
+
|
522
|
+
end
|
523
|
+
|
524
|
+
|
525
|
+
end
|
526
|
+
|
527
|
+
|
528
|
+
if __FILE__ == $0
|
529
|
+
CDNGet::Main.main()
|
530
|
+
end
|