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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9204fce30417104ddfeb1a49af1c1e770c630cc1
4
+ data.tar.gz: 1e9dc0c2d1fba34882a0dd5c6fc26a8ccc6edb57
5
+ SHA512:
6
+ metadata.gz: 087992a00501a6d1f3dd179a741b708eed1c80266666c0a61f8465325d2c7f0f7592ecc8015c3edb7e0987613a811e92fba0e4b7ecdb058a54b68f3f8a0b6f43
7
+ data.tar.gz: 1bed28d10dc90f2e2ab241178dc74a9762a866efe5860f31c2eab01a4f6377978653756932ddd8a2a170bbd9061fa3a77a78ecb5493dbf05b48ce0fdf76a27ce
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ $Copyright: copyright(c) 2016 kuwata-lab.com all rights reserved $
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,45 @@
1
+ CDNget
2
+ ======
3
+
4
+ ($Release: 0.1.0 $)
5
+
6
+ CDNget is a utility script to download files from CDNJS, jsDelivr or Google.
7
+
8
+
9
+ Install
10
+ -------
11
+
12
+ $ gem install cdnget
13
+
14
+ Or:
15
+
16
+ $ curl -sO https://github.com/kwatch/cdnget/raw/ruby-release/bin/cdnget
17
+ $ chmod a+x cdnget
18
+ $ sudo cp cdnget /usr/local/bin
19
+
20
+ CDNget is implemented in Ruby and requires Ruby >= 2.0.
21
+
22
+
23
+ Usage
24
+ -----
25
+
26
+ $ cdnget # list CDN (cdnjs/jsdelivr/google)
27
+ $ cdnget [-q] cdnjs # list libraries
28
+ $ cdnget [-q] cdnjs '*jquery*' # search libraries
29
+ $ cdnget [-q] cdnjs jquery # list library versions
30
+ $ cdnget [-q] cdnjs jquery 2.2.0 # list library files
31
+ $ cdnget [-q] cdnjs jquery 2.2.0 /tmp # download files
32
+ /tmp/jquery/2.2.0/jquery.js ... Done (258,388 byte)
33
+ /tmp/jquery/2.2.0/jquery.min.js ... Done (85,589 byte)
34
+ /tmp/jquery/2.2.0/jquery.min.map ... Done (129,544 byte)
35
+
36
+ $ ls /tmp/jquery/2.2.0
37
+ jquery.js jquery.min.js jquery.min.map
38
+
39
+
40
+ Copyright and License
41
+ ---------------------
42
+
43
+ $Copyright: copyright(c) 2016 kuwata-lab.com all rights reserved $
44
+
45
+ $License: MIT License $
@@ -0,0 +1,144 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ ###
4
+
5
+ RELEASE = '$Release: 0.1.0 $'.split()[1]
6
+ COPYRIGHT = 'copyright(c) 2016 kuwata-lab.com all rights reserved'
7
+ LICENSE = 'MIT License'
8
+
9
+ PROJECT = 'cdnget'
10
+
11
+
12
+ ### helpers
13
+
14
+ def run(command)
15
+ print '[rake]$ '; sh command
16
+ end
17
+
18
+ def edit_content(content, release=RELEASE)
19
+ s = content
20
+ s = s.gsub /\$Release\:.*?\$/, "$Release\: #{release} $"
21
+ s = s.gsub /\$Copyright\:.*?\$/, "$Copyright\: #{COPYRIGHT} $"
22
+ s = s.gsub /\$License\:.*?\$/, "$License\: #{LICENSE} $"
23
+ s = s.gsub /\$Release\$/, release
24
+ s = s.gsub /\$Copyright\$/, COPYRIGHT
25
+ s = s.gsub /\$License\$/, LICENSE
26
+ s
27
+ end
28
+
29
+ def load_gemspec
30
+ spec = eval File.read("#{PROJECT}.gemspec", encoding: 'utf-8')
31
+ return spec
32
+ end
33
+
34
+
35
+ ### tasks
36
+
37
+
38
+ #task :default => :test
39
+
40
+ desc "run test scripts"
41
+ task :test do
42
+ #sh "ruby -r minitest/autorun test/*_test.rb"
43
+ run "ruby test/#{PROJECT}_test.rb"
44
+ end
45
+
46
+
47
+ desc "remove *.rbc"
48
+ task :clean do
49
+ rm_f [Dir.glob("lib/**/*.rbc"), Dir.glob("test/**/*.rbc")]
50
+ end
51
+
52
+
53
+ desc "how to release"
54
+ task :howtorelease do
55
+ rel = ENV['rel'] || RELEASE
56
+ ver = rel.sub(/\.\d+$/,'')
57
+ patch_zero = !! (rel =~ /\.0$/)
58
+ puts <<END
59
+ $ git branch | grep '\*'
60
+ * ruby-dev
61
+ $ git checkout #{patch_zero ? '-b ': ''}ruby-#{ver}
62
+ $ rake edit rel=#{rel}
63
+ $ git diff
64
+ $ git commit -a -m "ruby: release preparation for #{rel}"
65
+ $ rake package
66
+ $ rake publish
67
+ END
68
+ end
69
+
70
+
71
+ desc "create 'bin/cdnget'"
72
+ task :bin do
73
+ material = "lib/cdnget.rb"
74
+ product = "bin/cdnget"
75
+ run %Q`cat #{material} | awk '{c=""}/if __FILE__/{f=1;c="#"}f&&/end/{c="#"}{print c $0}' > #{product}`
76
+ run %Q`chmod a+x #{product}`
77
+ end
78
+
79
+
80
+ desc "edit '$Release\:...$' in files"
81
+ task :edit => :bin do
82
+ rel = ENV['rel']
83
+ unless rel
84
+ $stderr.puts "*** Release number is not speicified"
85
+ $stderr.puts "*** Usage: rake edit rel=X.X.X"
86
+ raise StandardError
87
+ end
88
+ spec = load_gemspec()
89
+ spec.files.each do |fpath|
90
+ if fpath =~ /\.(gz|jpg|png|form)\z/
91
+ puts "[ignore] #{fpath}"
92
+ next
93
+ end
94
+ s1 = File.open(fpath, encoding: 'utf-8') {|f| f.read() }
95
+ s2 = edit_content(s1, rel)
96
+ if s1 == s2
97
+ puts "[skip] #{fpath}"
98
+ else
99
+ puts "[Edit] #{fpath}"
100
+ File.open(fpath, 'w', encoding: 'utf-8') {|f| f.write(s2) }
101
+ end
102
+ end
103
+ end
104
+
105
+
106
+ desc "create rubygem pacakge"
107
+ task :package do
108
+ spec = load_gemspec()
109
+ name = spec.name
110
+ ver = spec.version
111
+ run "gem build #{name}.gemspec"
112
+ puts ""
113
+ puts "## files"
114
+ puts spec.files.collect {|x| "- #{x}" }
115
+ end
116
+
117
+
118
+ desc "release gem"
119
+ task :publish do
120
+ diff = `git diff --stat`
121
+ if diff && ! diff.empty?
122
+ raise "[ERROR] Please commit changes before publishing gem."
123
+ end
124
+ #
125
+ spec = load_gemspec()
126
+ name = spec.name
127
+ ver = spec.version
128
+ #
129
+ gem = "#{name}-#{ver}.gem"
130
+ File.exist?(gem) or
131
+ raise "[ERROR] run 'rake package' before publishing gem."
132
+ mtime = File.mtime(gem)
133
+ ! spec.files.any? {|fpath| File.mtime(fpath) >= mtime } or
134
+ raise "[ERROR] run 'rake package' again because gem file seems obsoleted."
135
+ #
136
+ print "Upload #{gem}. OK? [y/N]: "
137
+ if $stdin.gets() =~ /[yY]/
138
+ run "gem push #{gem}"
139
+ run "git push -u origin `git rev-parse --abbrev-ref HEAD`"
140
+ run "git push -f origin ruby-release"
141
+ run "git tag ruby-#{ver}"
142
+ run "git push --tags"
143
+ end
144
+ end
@@ -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(/&#x2F;/, '/')
172
+ files << file.gsub(/&#x2F;/, '/')
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