jdc 0.1.2 → 0.2.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.
Files changed (151) hide show
  1. data/LICENSE +1277 -24
  2. data/Rakefile +13 -0
  3. data/bin/jdc +12 -2
  4. data/lib/admin/README.md +15 -0
  5. data/lib/admin/curl.rb +60 -0
  6. data/lib/admin/guid.rb +89 -0
  7. data/lib/admin/plugin.rb +6 -0
  8. data/lib/admin/service_auth_token.rb +94 -0
  9. data/lib/admin/service_broker/add.rb +47 -0
  10. data/lib/admin/service_broker/service_brokers.rb +24 -0
  11. data/lib/admin/set_quota.rb +44 -0
  12. data/lib/console/README.md +8 -0
  13. data/lib/console/console.rb +187 -0
  14. data/lib/console/plugin.rb +33 -0
  15. data/lib/jdc/cli/app/app.rb +43 -0
  16. data/lib/jdc/cli/app/apps.rb +87 -0
  17. data/lib/jdc/cli/app/base.rb +72 -0
  18. data/lib/jdc/cli/app/delete.rb +95 -0
  19. data/lib/jdc/cli/app/deprecated.rb +11 -0
  20. data/lib/jdc/cli/app/env.rb +78 -0
  21. data/lib/jdc/cli/app/events.rb +45 -0
  22. data/lib/jdc/cli/app/files.rb +137 -0
  23. data/lib/jdc/cli/app/health.rb +26 -0
  24. data/lib/jdc/cli/app/instances.rb +53 -0
  25. data/lib/jdc/cli/app/logs.rb +76 -0
  26. data/lib/jdc/cli/app/push/create.rb +108 -0
  27. data/lib/jdc/cli/app/push/interactions.rb +86 -0
  28. data/lib/jdc/cli/app/push/sync.rb +57 -0
  29. data/lib/jdc/cli/app/push.rb +103 -0
  30. data/lib/jdc/cli/app/rename.rb +35 -0
  31. data/lib/jdc/cli/app/restart.rb +31 -0
  32. data/lib/jdc/cli/app/scale.rb +63 -0
  33. data/lib/jdc/cli/app/start.rb +161 -0
  34. data/lib/jdc/cli/app/stats.rb +67 -0
  35. data/lib/jdc/cli/app/stop.rb +27 -0
  36. data/lib/jdc/cli/domain/base.rb +9 -0
  37. data/lib/jdc/cli/domain/domains.rb +40 -0
  38. data/lib/jdc/cli/domain/map.rb +55 -0
  39. data/lib/jdc/cli/domain/unmap.rb +56 -0
  40. data/lib/jdc/cli/help.rb +15 -0
  41. data/lib/jdc/cli/interactive.rb +105 -0
  42. data/lib/jdc/cli/login_requirements.rb +15 -0
  43. data/lib/jdc/cli/organization/base.rb +14 -0
  44. data/lib/jdc/cli/organization/create.rb +37 -0
  45. data/lib/jdc/cli/organization/delete.rb +63 -0
  46. data/lib/jdc/cli/organization/org.rb +45 -0
  47. data/lib/jdc/cli/organization/orgs.rb +30 -0
  48. data/lib/jdc/cli/organization/rename.rb +37 -0
  49. data/lib/jdc/cli/populators/base.rb +16 -0
  50. data/lib/jdc/cli/populators/organization.rb +32 -0
  51. data/lib/jdc/cli/populators/populator_methods.rb +64 -0
  52. data/lib/jdc/cli/populators/space.rb +33 -0
  53. data/lib/jdc/cli/populators/target.rb +13 -0
  54. data/lib/jdc/cli/route/base.rb +9 -0
  55. data/lib/jdc/cli/route/delete.rb +28 -0
  56. data/lib/jdc/cli/route/map.rb +68 -0
  57. data/lib/jdc/cli/route/routes.rb +26 -0
  58. data/lib/jdc/cli/route/unmap.rb +56 -0
  59. data/lib/jdc/cli/service/base.rb +9 -0
  60. data/lib/jdc/cli/service/bind.rb +44 -0
  61. data/lib/jdc/cli/service/create.rb +159 -0
  62. data/lib/jdc/cli/service/delete.rb +83 -0
  63. data/lib/jdc/cli/service/rename.rb +36 -0
  64. data/lib/jdc/cli/service/service.rb +42 -0
  65. data/lib/jdc/cli/service/service_instance_helper.rb +99 -0
  66. data/lib/jdc/cli/service/services.rb +111 -0
  67. data/lib/jdc/cli/service/unbind.rb +37 -0
  68. data/lib/jdc/cli/space/base.rb +29 -0
  69. data/lib/jdc/cli/space/create.rb +67 -0
  70. data/lib/jdc/cli/space/delete.rb +56 -0
  71. data/lib/jdc/cli/space/rename.rb +38 -0
  72. data/lib/jdc/cli/space/space.rb +66 -0
  73. data/lib/jdc/cli/space/spaces.rb +57 -0
  74. data/lib/jdc/cli/space/switch.rb +19 -0
  75. data/lib/jdc/cli/start/base.rb +41 -0
  76. data/lib/jdc/cli/start/colors.rb +13 -0
  77. data/lib/jdc/cli/start/target.rb +50 -0
  78. data/lib/jdc/cli/start/target_prettifier.rb +17 -0
  79. data/lib/jdc/cli/start/targets.rb +16 -0
  80. data/lib/jdc/cli/user/base.rb +30 -0
  81. data/lib/jdc/cli/user/create.rb +52 -0
  82. data/lib/jdc/cli/user/passwd.rb +37 -0
  83. data/lib/jdc/cli/user/register.rb +43 -0
  84. data/lib/jdc/cli/user/users.rb +32 -0
  85. data/lib/jdc/cli.rb +544 -0
  86. data/lib/jdc/constants.rb +11 -0
  87. data/lib/jdc/errors.rb +19 -0
  88. data/lib/jdc/object_extensions.rb +15 -0
  89. data/lib/jdc/plugin.rb +56 -0
  90. data/lib/jdc/spacing.rb +89 -0
  91. data/lib/jdc/spec_helper.rb +1 -0
  92. data/lib/jdc/test_support.rb +6 -0
  93. data/lib/jdc/version.rb +3 -0
  94. data/lib/jdc.rb +15 -2
  95. data/lib/manifests/errors.rb +35 -0
  96. data/lib/manifests/loader/builder.rb +39 -0
  97. data/lib/manifests/loader/normalizer.rb +145 -0
  98. data/lib/manifests/loader/resolver.rb +79 -0
  99. data/lib/manifests/loader.rb +31 -0
  100. data/lib/manifests/manifests.rb +344 -0
  101. data/lib/manifests/plugin.rb +140 -0
  102. data/lib/micro/README.md +9 -0
  103. data/lib/micro/errors.rb +4 -0
  104. data/lib/{jdc → micro}/micro.rb +15 -15
  105. data/lib/micro/plugin.rb +197 -0
  106. data/lib/micro/switcher/base.rb +79 -0
  107. data/lib/{jdc/micro → micro}/switcher/darwin.rb +5 -3
  108. data/lib/{jdc/micro → micro}/switcher/dummy.rb +1 -1
  109. data/lib/micro/switcher/linux.rb +16 -0
  110. data/lib/{jdc/micro → micro}/switcher/windows.rb +5 -5
  111. data/lib/{jdc/micro → micro}/vmrun.rb +26 -19
  112. data/lib/tasks/gem_release.rake +42 -0
  113. data/lib/tunnel/README.md +29 -0
  114. data/{config → lib/tunnel/config}/clients.yml +2 -2
  115. data/lib/tunnel/helper-app/Gemfile +10 -0
  116. data/lib/tunnel/helper-app/Gemfile.lock +48 -0
  117. data/{caldecott_helper → lib/tunnel/helper-app}/server.rb +5 -5
  118. data/lib/tunnel/plugin.rb +183 -0
  119. data/lib/tunnel/tunnel.rb +295 -0
  120. metadata +319 -89
  121. data/README.md +0 -102
  122. data/config/micro/paths.yml +0 -22
  123. data/config/micro/refresh_ip.rb +0 -20
  124. data/lib/cli/commands/admin.rb +0 -58
  125. data/lib/cli/commands/apps.rb +0 -1129
  126. data/lib/cli/commands/base.rb +0 -228
  127. data/lib/cli/commands/manifest.rb +0 -56
  128. data/lib/cli/commands/micro.rb +0 -115
  129. data/lib/cli/commands/misc.rb +0 -126
  130. data/lib/cli/commands/services.rb +0 -178
  131. data/lib/cli/commands/user.rb +0 -14
  132. data/lib/cli/config.rb +0 -173
  133. data/lib/cli/console_helper.rb +0 -170
  134. data/lib/cli/core_ext.rb +0 -122
  135. data/lib/cli/errors.rb +0 -19
  136. data/lib/cli/frameworks.rb +0 -265
  137. data/lib/cli/manifest_helper.rb +0 -302
  138. data/lib/cli/runner.rb +0 -505
  139. data/lib/cli/services_helper.rb +0 -84
  140. data/lib/cli/tunnel_helper.rb +0 -332
  141. data/lib/cli/usage.rb +0 -86
  142. data/lib/cli/version.rb +0 -7
  143. data/lib/cli/zip_util.rb +0 -77
  144. data/lib/cli.rb +0 -53
  145. data/lib/jdc/client.rb +0 -457
  146. data/lib/jdc/const.rb +0 -25
  147. data/lib/jdc/micro/switcher/base.rb +0 -97
  148. data/lib/jdc/micro/switcher/linux.rb +0 -16
  149. data/lib/jdc/signature/version.rb +0 -27
  150. data/lib/jdc/signer.rb +0 -13
  151. data/lib/jdc/timer.rb +0 -12
data/lib/jdc/cli.rb ADDED
@@ -0,0 +1,544 @@
1
+ require "yaml"
2
+ require "socket"
3
+ require "net/http"
4
+ require "multi_json"
5
+ require "fileutils"
6
+
7
+ require "mothership"
8
+
9
+ require "jfoundry"
10
+
11
+ require "jdc/constants"
12
+ require "jdc/errors"
13
+ require "jdc/spacing"
14
+
15
+ require "jdc/cli/help"
16
+ require "jdc/cli/interactive"
17
+ require "jdc/cli/login_requirements"
18
+
19
+
20
+ $cf_asked_auth = false
21
+
22
+ module JDC
23
+ class CLI < Mothership
24
+ include JDC::Interactive
25
+ include JDC::Spacing
26
+
27
+ option :help, :desc => "Show command usage", :alias => "-h",
28
+ :default => false
29
+
30
+ option :http_proxy, :desc => "Connect though an http proxy server", :alias => "--http-proxy",
31
+ :value => :http_proxy
32
+
33
+ option :https_proxy, :desc => "Connect though an https proxy server", :alias => "--https-proxy",
34
+ :value => :https_proxy
35
+
36
+ option :version, :desc => "Print version number", :alias => "-v",
37
+ :default => false
38
+
39
+ option :verbose, :desc => "Print extra information", :alias => "-V",
40
+ :default => false
41
+
42
+ option :force, :desc => "Skip interaction when possible", :alias => "-f",
43
+ :type => :boolean, :default => proc { input[:script] }
44
+
45
+ option :debug, :desc => "Print full stack trace (instead of crash log)",
46
+ :type => :boolean, :default => false
47
+
48
+ option :quiet, :desc => "Simplify output format", :alias => "-q",
49
+ :type => :boolean, :default => proc { input[:script] }
50
+
51
+ option :script, :desc => "Shortcut for --quiet and --force",
52
+ :type => :boolean, :default => proc { !$stdout.tty? }
53
+
54
+ option :color, :desc => "Use colorful output",
55
+ :type => :boolean, :default => proc { !input[:quiet] }
56
+
57
+ option :trace, :desc => "Show API traffic", :alias => "-t",
58
+ :default => false
59
+
60
+
61
+ def default_action
62
+ if input[:version]
63
+ line "jdc #{VERSION}"
64
+ else
65
+ super
66
+ end
67
+ end
68
+
69
+ def check_key
70
+ unless ENV["ACCESS_KEY"]
71
+ fail "Please set the env ACCESS_KEY."
72
+ end
73
+
74
+ unless ENV["SECRET_KEY"]
75
+ fail "Please set the env SECRET_KEY."
76
+ end
77
+ end
78
+
79
+ def check_target
80
+ unless client && client.target
81
+ fail "Please select a target with 'jdc target'."
82
+ end
83
+ end
84
+
85
+ def check_organization_and_space
86
+ info = target_info(client.target)
87
+
88
+ info_changed = false
89
+ if (info.key? :organization) && info[:access_key] != ENV['ACCESS_KEY']
90
+ info.delete(:organization)
91
+ client.current_organization = nil
92
+ info_changed = true
93
+ end
94
+
95
+ if (info.key? :space) && info[:access_key] != ENV['ACCESS_KEY']
96
+ info.delete(:space)
97
+ client.current_space = nil
98
+ info_changed = true
99
+ end
100
+
101
+ if info[:access_key] != ENV['ACCESS_KEY']
102
+ info[:access_key] = ENV['ACCESS_KEY']
103
+ info_changed = true
104
+ end
105
+
106
+ save_target_info(info, client.target) unless !info_changed
107
+ end
108
+
109
+ def check_logged_in
110
+ check_target
111
+ unless client.logged_in?
112
+ if force?
113
+ fail "Please log in with 'jdc login'."
114
+ else
115
+ line c("Please log in first to proceed.", :warning)
116
+ line
117
+ invoke :login
118
+ invalidate_client
119
+ end
120
+ end
121
+ end
122
+
123
+ desc "Help!"
124
+ input :command, :argument => :optional
125
+ def help
126
+ if name = input[:command]
127
+ if cmd = @@commands[name.gsub("-", "_").to_sym]
128
+ Mothership::Help.command_help(cmd)
129
+ else
130
+ unknown_command(name)
131
+ end
132
+ elsif Help.has_groups?
133
+ puts "#{help_header}"
134
+
135
+ Mothership::Help.print_help_groups(@@global, true)
136
+ else
137
+ Mothership::Help.basic_help(@@commands, @@global)
138
+ end
139
+ end
140
+
141
+ def help_header
142
+ <<EOS
143
+ Jing Dong Foundry Command Line Interface, version [#{JDC::VERSION}]
144
+ Use 'jdc help [command]' for command details.
145
+ For docs and support visit http://appengine.jd.com/help/jdc.html
146
+
147
+ USAGE EXAMPLES
148
+ $ jdc target api.jd-app.com <-- sets the JDC instance target where your app will be pushed
149
+ $ jdc push <-- deploys app to current app space on current target
150
+ $ jdc target -s staging <-- changes currently targeted app space to 'staging'
151
+
152
+ EOS
153
+ end
154
+
155
+ def wrap_errors
156
+ yield
157
+ rescue JFoundry::Timeout => e
158
+ err(e.message)
159
+ rescue Interrupt
160
+ exit_status 130
161
+ rescue Mothership::Error
162
+ raise
163
+ rescue UserError => e
164
+ log_error(e)
165
+ err e.message
166
+ rescue SystemExit
167
+ raise
168
+ rescue UserFriendlyError => e
169
+ err e.message
170
+ =begin
171
+ rescue JFoundry::InvalidAuthToken => e
172
+ line
173
+ line c("Invalid authentication token. Try logging in again with 'cf login'. If problems continue, please contact your Cloud Operator.", :warning)
174
+ rescue JFoundry::Forbidden => e
175
+ if !$cf_asked_auth
176
+ $cf_asked_auth = true
177
+
178
+ line
179
+ line c("Not authenticated! Try logging in:", :warning)
180
+
181
+ # TODO: there's no color here; global flags not being passed
182
+ # through (mothership bug?)
183
+ invoke :login
184
+
185
+ retry
186
+ end
187
+
188
+ log_error(e)
189
+
190
+ err "Denied: #{e.description}"
191
+ =end
192
+ rescue JFoundry::StagingError => e
193
+ message = "Application failed to stage"
194
+ formatted_exception_output(e, message)
195
+
196
+ rescue Exception => e
197
+ formatted_exception_output(e, add_exception_name_to_msg(e))
198
+ end
199
+
200
+ def formatted_exception_output(e, msg)
201
+ log_error(e)
202
+ msg << "\ncat #{JDC::CRASH_FILE} # for more details"
203
+ err msg
204
+
205
+ raise if debug?
206
+ end
207
+
208
+ def add_exception_name_to_msg(e)
209
+ msg = e.class.name
210
+ msg << ": #{e}" unless e.to_s.empty?
211
+ msg
212
+ end
213
+
214
+ def execute(cmd, argv, global = {})
215
+ if input[:help]
216
+ invoke :help, :command => cmd.name.to_s
217
+ else
218
+ wrap_errors do
219
+ @command = cmd
220
+ precondition if respond_to? :precondition
221
+
222
+ save_token_if_it_changes do
223
+ super
224
+ end
225
+ end
226
+ end
227
+ end
228
+
229
+ def save_token_if_it_changes
230
+ return yield unless client
231
+ yield
232
+ =begin
233
+ return yield unless client && client.token
234
+
235
+ before_token = client.token
236
+
237
+ yield
238
+
239
+ after_token = client.token
240
+
241
+ return unless after_token
242
+
243
+ if before_token != after_token
244
+ info = target_info
245
+ info[:token] = after_token.auth_header
246
+ save_target_info(info)
247
+ end
248
+ =end
249
+ end
250
+
251
+ def log_error(e)
252
+ ensure_config_dir
253
+
254
+ msg = e.class.name
255
+ msg << ": #{e}" unless e.to_s.empty?
256
+
257
+ crash_file = File.expand_path(JDC::CRASH_FILE)
258
+
259
+ FileUtils.mkdir_p(File.dirname(crash_file))
260
+
261
+ File.open(crash_file, "w") do |f|
262
+ f.puts "Time of crash:"
263
+ f.puts " #{Time.now}"
264
+ f.puts ""
265
+ f.puts msg
266
+ f.puts ""
267
+
268
+ if e.respond_to?(:request_trace)
269
+ f.puts "<<<"
270
+ f.puts e.request_trace
271
+ end
272
+
273
+ if e.respond_to?(:response_trace)
274
+ f.puts e.response_trace
275
+ f.puts ">>>"
276
+ f.puts ""
277
+ end
278
+
279
+ jdc_dir = File.expand_path("../../../..", __FILE__) + "/"
280
+ e.backtrace.each do |loc|
281
+ if loc =~ /\/gems\//
282
+ f.puts loc.sub(/.*\/gems\//, "")
283
+ else
284
+ f.puts loc.sub(jdc_dir, "")
285
+ end
286
+ end
287
+ end
288
+ end
289
+
290
+ def quiet?
291
+ input[:quiet]
292
+ end
293
+
294
+ def force?
295
+ input[:force]
296
+ end
297
+
298
+ def debug?
299
+ !!input[:debug]
300
+ end
301
+
302
+ def color_enabled?
303
+ input[:color]
304
+ end
305
+
306
+ def verbose?
307
+ input[:verbose]
308
+ end
309
+
310
+ def user_colors
311
+ return @user_colors if @user_colors
312
+
313
+ colors = File.expand_path(COLORS_FILE)
314
+
315
+ @user_colors = super.dup
316
+
317
+ # most terminal schemes are stupid, so use cyan instead
318
+ @user_colors.each do |k, v|
319
+ if v == :blue
320
+ @user_colors[k] = :cyan
321
+ end
322
+ end
323
+
324
+ if File.exists?(colors)
325
+ YAML.load_file(colors).each do |k, v|
326
+ @user_colors[k.to_sym] = v.to_sym
327
+ end
328
+ end
329
+
330
+ @user_colors
331
+ end
332
+
333
+ def err(msg, status = 1)
334
+ $stderr.puts c(msg, :error)
335
+ exit_status status
336
+ end
337
+
338
+ def fail(msg)
339
+ raise UserError, msg
340
+ end
341
+
342
+ def table(headers, rows)
343
+ tabular(
344
+ !quiet? && headers.collect { |h| h && b(h) },
345
+ *rows)
346
+ end
347
+
348
+ def name_list(xs)
349
+ if xs.empty?
350
+ d("none")
351
+ else
352
+ xs.collect { |x| c(x.name, :name) }.join(", ")
353
+ end
354
+ end
355
+
356
+ def sane_target_url(url)
357
+ unless url =~ /^https?:\/\//
358
+ begin
359
+ TCPSocket.new(url, Net::HTTP.https_default_port)
360
+ url = "https://#{url}"
361
+ rescue Errno::ECONNREFUSED, SocketError, Timeout::Error
362
+ url = "http://#{url}"
363
+ end
364
+ end
365
+
366
+ url.gsub(/\/$/, "")
367
+ end
368
+
369
+ def one_of(*paths)
370
+ paths.each do |p|
371
+ exp = File.expand_path(p)
372
+ return exp if File.exist? exp
373
+ end
374
+
375
+ File.expand_path(paths.first)
376
+ end
377
+
378
+ def client_target
379
+ return File.read(target_file).chomp if File.exists?(target_file)
380
+ sane_target_url(JDC::DEFAULT_API_URL)
381
+ end
382
+
383
+ def ensure_config_dir
384
+ config = File.expand_path(JDC::CONFIG_DIR)
385
+ FileUtils.mkdir_p(config) unless File.exist? config
386
+ end
387
+
388
+ def set_target(url)
389
+ ensure_config_dir
390
+
391
+ File.open(File.expand_path(JDC::TARGET_FILE), "w") do |f|
392
+ f.write(sane_target_url(url))
393
+ end
394
+
395
+ invalidate_client
396
+ end
397
+
398
+ def targets_info
399
+ new_toks = File.expand_path(JDC::TOKENS_FILE)
400
+
401
+ info =
402
+ if File.exist? new_toks
403
+ YAML.load_file(new_toks)
404
+ end
405
+
406
+ info ||= {}
407
+
408
+ normalize_targets_info(info)
409
+ end
410
+
411
+ def normalize_targets_info(info_by_url)
412
+ info_by_url.reduce({}) do |hash, pair|
413
+ key, value = pair
414
+ hash[key] = value.is_a?(String) ? { :token => value } : value
415
+ hash
416
+ end
417
+ end
418
+
419
+ def target_info(target = client_target)
420
+ targets_info[target] || {}
421
+ end
422
+
423
+ def save_targets(ts)
424
+ ensure_config_dir
425
+
426
+ File.open(File.expand_path(JDC::TOKENS_FILE), "w") do |io|
427
+ YAML.dump(ts, io)
428
+ end
429
+ end
430
+
431
+ def save_target_info(info, target = client_target)
432
+ ts = targets_info
433
+ ts[target] = info
434
+ save_targets(ts)
435
+ end
436
+
437
+ def remove_target_info(target = client_target)
438
+ ts = targets_info
439
+ ts.delete target
440
+ save_targets(ts)
441
+ end
442
+
443
+ def invalidate_client
444
+ @@client = nil
445
+ client
446
+ end
447
+
448
+ def client(target = client_target)
449
+ return @@client if defined?(@@client) && @@client
450
+ return unless target
451
+
452
+ info = target_info(target)
453
+ #token = info[:token] && JFoundry::AuthToken.from_hash(info)
454
+
455
+ fail "V1 targets are no longer supported." if info[:version] == 1
456
+
457
+ @@client = build_client(target)
458
+
459
+ @@client.trace = input[:trace]
460
+
461
+ uri = URI.parse(target)
462
+ @@client.log = File.expand_path("#{LOGS_DIR}/#{uri.host}.log")
463
+
464
+ info_changed = false
465
+ unless info.key? :version
466
+ info[:version] = @@client.version
467
+ info_changed = true
468
+ end
469
+
470
+ unless info.key? :access_key
471
+ info[:access_key] = ENV['ACCESS_KEY']
472
+ info_changed = true
473
+ end
474
+
475
+ save_target_info(info, target) unless !info_changed
476
+
477
+ @@client.current_organization = @@client.organization(info[:organization]) if info[:organization]
478
+ @@client.current_space = @@client.space(info[:space]) if info[:space]
479
+
480
+ @@client
481
+ rescue JFoundry::InvalidTarget
482
+ end
483
+
484
+ def build_client(target)
485
+ client = JFoundry::V2::Client.new(target, ENV['ACCESS_KEY'], ENV['SECRET_KEY'], JDC::VERSION)
486
+ client.http_proxy = input[:http_proxy] || ENV['HTTP_PROXY'] || ENV['http_proxy']
487
+ client.https_proxy = input[:https_proxy] || ENV['HTTPS_PROXY'] || ENV['https_proxy']
488
+ client
489
+ end
490
+
491
+ def fail_unknown(display, name)
492
+ fail("Unknown #{display} '#{name}'.")
493
+ end
494
+
495
+ class << self
496
+ def client
497
+ @@client
498
+ end
499
+
500
+ def client=(c)
501
+ @@client = c
502
+ end
503
+
504
+ private
505
+
506
+ def find_by_name(display, &blk)
507
+ proc { |name, *args|
508
+ choices, _ = args
509
+ choices ||= instance_exec(&blk) if block_given?
510
+
511
+ choices.find { |c| c.name == name } ||
512
+ fail_unknown(display, name)
513
+ }
514
+ end
515
+
516
+ def by_name(what, display = what)
517
+ proc { |name, *_|
518
+ client.send(:"#{what}_by_name", name) ||
519
+ fail_unknown(display, name)
520
+ }
521
+ end
522
+
523
+ def find_by_name_insensitive(display, &blk)
524
+ proc { |name, *args|
525
+ choices, _ = args
526
+ choices ||= instance_exec(&blk) if block_given?
527
+
528
+ choices.find { |c| c.name.upcase == name.upcase } ||
529
+ fail_unknown(display, name)
530
+ }
531
+ end
532
+ end
533
+
534
+ private
535
+
536
+ def target_file
537
+ File.expand_path(JDC::TARGET_FILE)
538
+ end
539
+
540
+ def tokens_file
541
+ File.expand_path(JDC::TOKENS_FILE)
542
+ end
543
+ end
544
+ end
@@ -0,0 +1,11 @@
1
+ module JDC
2
+ CONFIG_DIR = "~/.jdc".freeze
3
+
4
+ LOGS_DIR = "#{CONFIG_DIR}/logs".freeze
5
+ PLUGINS_FILE = "#{CONFIG_DIR}/plugins.yml".freeze
6
+ TARGET_FILE = "#{CONFIG_DIR}/target".freeze
7
+ TOKENS_FILE = "#{CONFIG_DIR}/tokens.yml".freeze
8
+ COLORS_FILE = "#{CONFIG_DIR}/colors.yml".freeze
9
+ CRASH_FILE = "#{CONFIG_DIR}/crash".freeze
10
+ DEFAULT_API_URL = "api.jd-app.com".freeze
11
+ end
data/lib/jdc/errors.rb ADDED
@@ -0,0 +1,19 @@
1
+ module JDC
2
+ class UserFriendlyError < RuntimeError
3
+ def initialize(msg)
4
+ @message = msg
5
+ end
6
+
7
+ def to_s
8
+ @message
9
+ end
10
+ end
11
+
12
+ class UserError < UserFriendlyError; end
13
+
14
+ class NotAuthorized < UserError
15
+ def initialize
16
+ @message = "Not authorized."
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,15 @@
1
+ class Object
2
+ def try(*a, &b)
3
+ if a.empty? && block_given?
4
+ yield self
5
+ else
6
+ __send__(*a, &b)
7
+ end
8
+ end
9
+ end
10
+
11
+ class NilClass
12
+ def try(*a, &b)
13
+ nil
14
+ end
15
+ end
data/lib/jdc/plugin.rb ADDED
@@ -0,0 +1,56 @@
1
+ require "set"
2
+ require "yaml"
3
+
4
+ require "jdc/constants"
5
+ require "jdc/cli"
6
+
7
+ module JDC
8
+ module Plugin
9
+ @@plugins = []
10
+
11
+ def self.load_all
12
+ # auto-load gems with 'jdc-plugin' in their name
13
+ matching =
14
+ if Gem::Specification.respond_to? :find_all
15
+ Gem::Specification.find_all do |s|
16
+ s.name =~ /jdc-plugin/
17
+ end
18
+ else
19
+ Gem.source_index.find_name(/jdc-plugin/)
20
+ end
21
+
22
+ enabled = Set.new(matching.collect(&:name))
23
+
24
+ jdc_gems = Gem.loaded_specs["jdc"]
25
+ ((jdc_gems && jdc_gems.dependencies) || Gem.loaded_specs.values).each do |dep|
26
+ if dep.name =~ /jdc-plugin/
27
+ require "#{dep.name}/plugin"
28
+ enabled.delete dep.name
29
+ end
30
+ end
31
+
32
+ # allow explicit enabling/disabling of gems via config
33
+ plugins = File.expand_path(JDC::PLUGINS_FILE)
34
+ if File.exists?(plugins) && yaml = YAML.load_file(plugins)
35
+ enabled += yaml["enabled"] if yaml["enabled"]
36
+ enabled -= yaml["disabled"] if yaml["disabled"]
37
+ end
38
+
39
+ # load up each gem's 'plugin' file
40
+ #
41
+ # we require this file specifically so people can require the gem
42
+ # without it plugging into JDC
43
+ enabled.each do |gemname|
44
+ begin
45
+ require "#{gemname}/plugin"
46
+ rescue Gem::LoadError => e
47
+ puts "Failed to load #{gemname}:"
48
+ puts " #{e}"
49
+ puts
50
+ puts "You may need to update or remove this plugin."
51
+ puts
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end