jdc 0.2.1.pre → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (151) hide show
  1. data/LICENSE +24 -1277
  2. data/README.md +102 -0
  3. data/bin/jdc +2 -12
  4. data/{lib/tunnel/helper-app → caldecott_helper}/server.rb +5 -5
  5. data/{lib/tunnel/config → config}/clients.yml +2 -2
  6. data/config/micro/paths.yml +22 -0
  7. data/config/micro/refresh_ip.rb +20 -0
  8. data/lib/cli/commands/admin.rb +58 -0
  9. data/lib/cli/commands/apps.rb +1129 -0
  10. data/lib/cli/commands/base.rb +228 -0
  11. data/lib/cli/commands/manifest.rb +56 -0
  12. data/lib/cli/commands/micro.rb +115 -0
  13. data/lib/cli/commands/misc.rb +126 -0
  14. data/lib/cli/commands/services.rb +178 -0
  15. data/lib/cli/commands/user.rb +14 -0
  16. data/lib/cli/config.rb +173 -0
  17. data/lib/cli/console_helper.rb +170 -0
  18. data/lib/cli/core_ext.rb +122 -0
  19. data/lib/cli/errors.rb +19 -0
  20. data/lib/cli/frameworks.rb +265 -0
  21. data/lib/cli/manifest_helper.rb +300 -0
  22. data/lib/cli/runner.rb +505 -0
  23. data/lib/cli/services_helper.rb +84 -0
  24. data/lib/cli/tunnel_helper.rb +332 -0
  25. data/lib/cli/usage.rb +86 -0
  26. data/lib/cli/version.rb +7 -0
  27. data/lib/cli/zip_util.rb +77 -0
  28. data/lib/cli.rb +53 -0
  29. data/lib/jdc/client.rb +457 -0
  30. data/lib/jdc/const.rb +25 -0
  31. data/lib/jdc/micro/switcher/base.rb +97 -0
  32. data/lib/{micro → jdc/micro}/switcher/darwin.rb +3 -5
  33. data/lib/{micro → jdc/micro}/switcher/dummy.rb +1 -1
  34. data/lib/jdc/micro/switcher/linux.rb +16 -0
  35. data/lib/{micro → jdc/micro}/switcher/windows.rb +5 -5
  36. data/lib/{micro → jdc/micro}/vmrun.rb +19 -26
  37. data/lib/{micro → jdc}/micro.rb +15 -15
  38. data/lib/jdc/signature/version.rb +27 -0
  39. data/lib/jdc/signer.rb +13 -0
  40. data/lib/jdc/timer.rb +12 -0
  41. data/lib/jdc.rb +2 -15
  42. metadata +210 -360
  43. data/Rakefile +0 -13
  44. data/lib/admin/README.md +0 -15
  45. data/lib/admin/curl.rb +0 -60
  46. data/lib/admin/guid.rb +0 -89
  47. data/lib/admin/plugin.rb +0 -6
  48. data/lib/admin/service_auth_token.rb +0 -94
  49. data/lib/admin/service_broker/add.rb +0 -47
  50. data/lib/admin/service_broker/service_brokers.rb +0 -24
  51. data/lib/admin/set_quota.rb +0 -44
  52. data/lib/console/README.md +0 -8
  53. data/lib/console/console.rb +0 -187
  54. data/lib/console/plugin.rb +0 -33
  55. data/lib/jdc/cli/app/app.rb +0 -43
  56. data/lib/jdc/cli/app/apps.rb +0 -87
  57. data/lib/jdc/cli/app/base.rb +0 -72
  58. data/lib/jdc/cli/app/delete.rb +0 -95
  59. data/lib/jdc/cli/app/deprecated.rb +0 -11
  60. data/lib/jdc/cli/app/env.rb +0 -78
  61. data/lib/jdc/cli/app/events.rb +0 -45
  62. data/lib/jdc/cli/app/files.rb +0 -137
  63. data/lib/jdc/cli/app/health.rb +0 -26
  64. data/lib/jdc/cli/app/instances.rb +0 -53
  65. data/lib/jdc/cli/app/logs.rb +0 -76
  66. data/lib/jdc/cli/app/push/create.rb +0 -108
  67. data/lib/jdc/cli/app/push/interactions.rb +0 -86
  68. data/lib/jdc/cli/app/push/sync.rb +0 -57
  69. data/lib/jdc/cli/app/push.rb +0 -103
  70. data/lib/jdc/cli/app/rename.rb +0 -35
  71. data/lib/jdc/cli/app/restart.rb +0 -31
  72. data/lib/jdc/cli/app/scale.rb +0 -63
  73. data/lib/jdc/cli/app/start.rb +0 -161
  74. data/lib/jdc/cli/app/stats.rb +0 -67
  75. data/lib/jdc/cli/app/stop.rb +0 -27
  76. data/lib/jdc/cli/domain/base.rb +0 -9
  77. data/lib/jdc/cli/domain/domains.rb +0 -40
  78. data/lib/jdc/cli/domain/map.rb +0 -55
  79. data/lib/jdc/cli/domain/unmap.rb +0 -56
  80. data/lib/jdc/cli/help.rb +0 -15
  81. data/lib/jdc/cli/interactive.rb +0 -105
  82. data/lib/jdc/cli/login_requirements.rb +0 -15
  83. data/lib/jdc/cli/organization/base.rb +0 -14
  84. data/lib/jdc/cli/organization/create.rb +0 -37
  85. data/lib/jdc/cli/organization/delete.rb +0 -63
  86. data/lib/jdc/cli/organization/org.rb +0 -45
  87. data/lib/jdc/cli/organization/orgs.rb +0 -30
  88. data/lib/jdc/cli/organization/rename.rb +0 -37
  89. data/lib/jdc/cli/populators/base.rb +0 -16
  90. data/lib/jdc/cli/populators/organization.rb +0 -32
  91. data/lib/jdc/cli/populators/populator_methods.rb +0 -64
  92. data/lib/jdc/cli/populators/space.rb +0 -33
  93. data/lib/jdc/cli/populators/target.rb +0 -13
  94. data/lib/jdc/cli/route/base.rb +0 -9
  95. data/lib/jdc/cli/route/delete.rb +0 -28
  96. data/lib/jdc/cli/route/map.rb +0 -68
  97. data/lib/jdc/cli/route/routes.rb +0 -26
  98. data/lib/jdc/cli/route/unmap.rb +0 -56
  99. data/lib/jdc/cli/service/base.rb +0 -9
  100. data/lib/jdc/cli/service/bind.rb +0 -44
  101. data/lib/jdc/cli/service/create.rb +0 -159
  102. data/lib/jdc/cli/service/delete.rb +0 -83
  103. data/lib/jdc/cli/service/rename.rb +0 -36
  104. data/lib/jdc/cli/service/service.rb +0 -42
  105. data/lib/jdc/cli/service/service_instance_helper.rb +0 -99
  106. data/lib/jdc/cli/service/services.rb +0 -111
  107. data/lib/jdc/cli/service/unbind.rb +0 -37
  108. data/lib/jdc/cli/space/base.rb +0 -29
  109. data/lib/jdc/cli/space/create.rb +0 -67
  110. data/lib/jdc/cli/space/delete.rb +0 -56
  111. data/lib/jdc/cli/space/rename.rb +0 -38
  112. data/lib/jdc/cli/space/space.rb +0 -66
  113. data/lib/jdc/cli/space/spaces.rb +0 -57
  114. data/lib/jdc/cli/space/switch.rb +0 -19
  115. data/lib/jdc/cli/start/base.rb +0 -41
  116. data/lib/jdc/cli/start/colors.rb +0 -13
  117. data/lib/jdc/cli/start/target.rb +0 -50
  118. data/lib/jdc/cli/start/target_prettifier.rb +0 -17
  119. data/lib/jdc/cli/start/targets.rb +0 -16
  120. data/lib/jdc/cli/user/base.rb +0 -30
  121. data/lib/jdc/cli/user/create.rb +0 -52
  122. data/lib/jdc/cli/user/passwd.rb +0 -37
  123. data/lib/jdc/cli/user/register.rb +0 -43
  124. data/lib/jdc/cli/user/users.rb +0 -32
  125. data/lib/jdc/cli.rb +0 -556
  126. data/lib/jdc/constants.rb +0 -11
  127. data/lib/jdc/errors.rb +0 -19
  128. data/lib/jdc/object_extensions.rb +0 -15
  129. data/lib/jdc/plugin.rb +0 -56
  130. data/lib/jdc/spacing.rb +0 -89
  131. data/lib/jdc/spec_helper.rb +0 -1
  132. data/lib/jdc/test_support.rb +0 -6
  133. data/lib/jdc/version.rb +0 -3
  134. data/lib/manifests/errors.rb +0 -35
  135. data/lib/manifests/loader/builder.rb +0 -39
  136. data/lib/manifests/loader/normalizer.rb +0 -145
  137. data/lib/manifests/loader/resolver.rb +0 -79
  138. data/lib/manifests/loader.rb +0 -31
  139. data/lib/manifests/manifests.rb +0 -344
  140. data/lib/manifests/plugin.rb +0 -140
  141. data/lib/micro/README.md +0 -9
  142. data/lib/micro/errors.rb +0 -4
  143. data/lib/micro/plugin.rb +0 -197
  144. data/lib/micro/switcher/base.rb +0 -79
  145. data/lib/micro/switcher/linux.rb +0 -16
  146. data/lib/tasks/gem_release.rake +0 -42
  147. data/lib/tunnel/README.md +0 -29
  148. data/lib/tunnel/helper-app/Gemfile +0 -10
  149. data/lib/tunnel/helper-app/Gemfile.lock +0 -48
  150. data/lib/tunnel/plugin.rb +0 -183
  151. data/lib/tunnel/tunnel.rb +0 -295
data/lib/cli/config.rb ADDED
@@ -0,0 +1,173 @@
1
+ require "yaml"
2
+ require 'fileutils'
3
+
4
+ require 'rubygems'
5
+ require 'json/pure'
6
+
7
+ module JDC::Cli
8
+ class Config
9
+
10
+ DEFAULT_TARGET = 'api.jd-app.com'
11
+
12
+ TARGET_FILE = '~/.jdc_target'
13
+ TOKEN_FILE = '~/.jdc_token'
14
+ INSTANCES_FILE = '~/.jdc_instances'
15
+ ALIASES_FILE = '~/.jdc_aliases'
16
+ CLIENTS_FILE = '~/.jdc_clients'
17
+ MICRO_FILE = '~/.jdc_micro'
18
+
19
+ STOCK_CLIENTS = File.expand_path("../../../config/clients.yml", __FILE__)
20
+
21
+ class << self
22
+ attr_accessor :colorize
23
+ attr_accessor :output
24
+ attr_accessor :trace
25
+ attr_accessor :nozip
26
+
27
+ def target_url
28
+ return @target_url if @target_url
29
+ target_file = File.expand_path(TARGET_FILE)
30
+ if File.exists? target_file
31
+ @target_url = lock_and_read(target_file).strip
32
+ else
33
+ @target_url = DEFAULT_TARGET
34
+ end
35
+ @target_url = "http://#{@target_url}" unless /^https?/ =~ @target_url
36
+ @target_url = @target_url.gsub(/\/+$/, '')
37
+ @target_url
38
+ end
39
+
40
+ def base_of(url)
41
+ url.sub(/^[^\.]+\./, "")
42
+ end
43
+
44
+ def suggest_url
45
+ @suggest_url ||= base_of(target_url)
46
+ end
47
+
48
+ def store_target(target_host)
49
+ target_file = File.expand_path(TARGET_FILE)
50
+ lock_and_write(target_file, target_host)
51
+ end
52
+
53
+ def all_tokens(token_file_path=nil)
54
+ token_file = File.expand_path(token_file_path || TOKEN_FILE)
55
+ return nil unless File.exists? token_file
56
+ contents = lock_and_read(token_file).strip
57
+ JSON.parse(contents)
58
+ end
59
+
60
+ alias :targets :all_tokens
61
+
62
+ def auth_token(token_file_path=nil)
63
+ return @token if @token
64
+ tokens = all_tokens(token_file_path)
65
+ @token = tokens[target_url] if tokens
66
+ end
67
+
68
+ def remove_token_file
69
+ FileUtils.rm_f(File.expand_path(TOKEN_FILE))
70
+ end
71
+
72
+ def store_token(token, token_file_path=nil)
73
+ tokens = all_tokens(token_file_path) || {}
74
+ tokens[target_url] = token
75
+ token_file = File.expand_path(token_file_path || TOKEN_FILE)
76
+ lock_and_write(token_file, tokens.to_json)
77
+ end
78
+
79
+ def instances
80
+ instances_file = File.expand_path(INSTANCES_FILE)
81
+ return nil unless File.exists? instances_file
82
+ contents = lock_and_read(instances_file).strip
83
+ JSON.parse(contents)
84
+ end
85
+
86
+ def store_instances(instances)
87
+ instances_file = File.expand_path(INSTANCES_FILE)
88
+ lock_and_write(instances_file, instances.to_json)
89
+ end
90
+
91
+ def aliases
92
+ aliases_file = File.expand_path(ALIASES_FILE)
93
+ # bacward compatible
94
+ unless File.exists? aliases_file
95
+ old_aliases_file = File.expand_path('~/.jdc-aliases')
96
+ FileUtils.mv(old_aliases_file, aliases_file) if File.exists? old_aliases_file
97
+ end
98
+ aliases = YAML.load_file(aliases_file) rescue {}
99
+ end
100
+
101
+ def store_aliases(aliases)
102
+ aliases_file = File.expand_path(ALIASES_FILE)
103
+ File.open(aliases_file, 'wb') {|f| f.write(aliases.to_yaml)}
104
+ end
105
+
106
+ def micro
107
+ micro_file = File.expand_path(MICRO_FILE)
108
+ return {} unless File.exists? micro_file
109
+ contents = lock_and_read(micro_file).strip
110
+ JSON.parse(contents)
111
+ end
112
+
113
+ def store_micro(micro)
114
+ micro_file = File.expand_path(MICRO_FILE)
115
+ lock_and_write(micro_file, micro.to_json)
116
+ end
117
+
118
+ def deep_merge(a, b)
119
+ merge = proc do |_, old, new|
120
+ if new.is_a?(Hash) and old.is_a?(Hash)
121
+ old.merge(new, &merge)
122
+ else
123
+ new
124
+ end
125
+ end
126
+
127
+ a.merge(b, &merge)
128
+ end
129
+
130
+ def clients
131
+ return @clients if @clients
132
+
133
+ stock = YAML.load_file(STOCK_CLIENTS)
134
+ clients = File.expand_path CLIENTS_FILE
135
+ if File.exists? clients
136
+ user = YAML.load_file(clients)
137
+ @clients = deep_merge(stock, user)
138
+ else
139
+ @clients = stock
140
+ end
141
+ end
142
+
143
+ def lock_and_read(file)
144
+ File.open(file, File::RDONLY) {|f|
145
+ if defined? JRUBY_VERSION
146
+ f.flock(File::LOCK_SH)
147
+ else
148
+ f.flock(File::LOCK_EX)
149
+ end
150
+ contents = f.read
151
+ f.flock(File::LOCK_UN)
152
+ contents
153
+ }
154
+ end
155
+
156
+ def lock_and_write(file, contents)
157
+ File.open(file, File::RDWR | File::CREAT, 0600) {|f|
158
+ f.flock(File::LOCK_EX)
159
+ f.rewind
160
+ f.puts contents
161
+ f.flush
162
+ f.truncate(f.pos)
163
+ f.flock(File::LOCK_UN)
164
+ }
165
+ end
166
+ end
167
+
168
+ def initialize(work_dir = Dir.pwd)
169
+ @work_dir = work_dir
170
+ end
171
+
172
+ end
173
+ end
@@ -0,0 +1,170 @@
1
+ require 'net/telnet'
2
+ require 'readline'
3
+
4
+ module JDC::Cli
5
+ module ConsoleHelper
6
+
7
+ def console_connection_info(appname)
8
+ app = client.app_info(appname)
9
+ fw = JDC::Cli::Framework.lookup_by_framework(app[:staging][:model])
10
+ if !fw.console
11
+ err "'#{appname}' is a #{fw.name} application. " +
12
+ "Console access is not supported for #{fw.name} applications."
13
+ end
14
+ instances_info_envelope = client.app_instances(appname)
15
+ instances_info_envelope = {} if instances_info_envelope.is_a?(Array)
16
+
17
+ instances_info = instances_info_envelope[:instances] || []
18
+ err "No running instances for [#{appname}]" if instances_info.empty?
19
+
20
+ entry = instances_info[0]
21
+ if !entry[:console_port]
22
+ begin
23
+ client.app_files(appname, '/app/cf-rails-console')
24
+ err "Console port not provided for [#{appname}]. Try restarting the app."
25
+ rescue JDC::Client::TargetError, JDC::Client::NotFound
26
+ err "Console access not supported for [#{appname}]. " +
27
+ "Please redeploy your app to enable support."
28
+ end
29
+ end
30
+ conn_info = {'hostname' => entry[:console_ip], 'port' => entry[:console_port]}
31
+ end
32
+
33
+ def start_local_console(port, appname)
34
+ auth_info = console_credentials(appname)
35
+ banner = "Connecting to '#{appname}' console: "
36
+ display banner, false
37
+ t = Thread.new do
38
+ count = 0
39
+ while count < 90 do
40
+ display '.', false
41
+ sleep 1
42
+ count += 1
43
+ end
44
+ end
45
+ prompt = console_login(auth_info, port)
46
+ Thread.kill(t)
47
+ clear(80)
48
+ display "#{banner}#{'OK'.green}"
49
+ display "\n"
50
+ initialize_readline
51
+ run_console prompt
52
+ end
53
+
54
+ def console_login(auth_info, port)
55
+ if !auth_info["username"] || !auth_info["password"]
56
+ err "Unable to verify console credentials."
57
+ end
58
+ @telnet_client = telnet_client(port)
59
+ prompt = nil
60
+ err_msg = "Login attempt timed out."
61
+ 3.times do
62
+ begin
63
+ results = @telnet_client.login("Name"=>auth_info["username"],
64
+ "Password"=>auth_info["password"])
65
+ lines = results.sub("Login: Password: ", "").split("\n")
66
+ last_line = lines.pop
67
+ if last_line =~ /[$%#>] \z/n
68
+ prompt = last_line
69
+ elsif last_line =~ /Login failed/
70
+ err_msg = last_line
71
+ end
72
+ break
73
+ rescue TimeoutError
74
+ sleep 1
75
+ rescue EOFError
76
+ #This may happen if we login right after app starts
77
+ close_console
78
+ sleep 5
79
+ @telnet_client = telnet_client(port)
80
+ end
81
+ end
82
+ unless prompt
83
+ close_console
84
+ err err_msg
85
+ end
86
+ prompt
87
+ end
88
+
89
+ def send_console_command(cmd)
90
+ results = @telnet_client.cmd(cmd)
91
+ results.split("\n")
92
+ end
93
+
94
+ def console_credentials(appname)
95
+ content = client.app_files(appname, '/app/cf-rails-console/.consoleaccess', '0')
96
+ YAML.load(content)
97
+ end
98
+
99
+ def close_console
100
+ @telnet_client.close
101
+ end
102
+
103
+ def console_tab_completion_data(cmd)
104
+ begin
105
+ results = @telnet_client.cmd("String"=> cmd + "\t", "Match"=>/\S*\n$/, "Timeout"=>10)
106
+ results.chomp.split(",")
107
+ rescue TimeoutError
108
+ [] #Just return empty results if timeout occurred on tab completion
109
+ end
110
+ end
111
+
112
+ private
113
+ def telnet_client(port)
114
+ Net::Telnet.new({"Port"=>port, "Prompt"=>/[$%#>] \z|Login failed/n, "Timeout"=>30, "FailEOF"=>true})
115
+ end
116
+
117
+ def readline_with_history(prompt)
118
+ line = Readline::readline(prompt)
119
+ return nil if line == nil || line == 'quit' || line == 'exit'
120
+ Readline::HISTORY.push(line) if not line =~ /^\s*$/ and Readline::HISTORY.to_a[-1] != line
121
+ line
122
+ end
123
+
124
+ def run_console(prompt)
125
+ prev = trap("INT") { |x| exit_console; prev.call(x); exit }
126
+ prev = trap("TERM") { |x| exit_console; prev.call(x); exit }
127
+ loop do
128
+ cmd = readline_with_history(prompt)
129
+ if(cmd == nil)
130
+ exit_console
131
+ break
132
+ end
133
+ prompt = send_console_command_display_results(cmd, prompt)
134
+ end
135
+ end
136
+
137
+ def exit_console
138
+ #TimeoutError expected, as exit doesn't return anything
139
+ @telnet_client.cmd("String"=>"exit","Timeout"=>1) rescue TimeoutError
140
+ close_console
141
+ end
142
+
143
+ def send_console_command_display_results(cmd, prompt)
144
+ begin
145
+ lines = send_console_command cmd
146
+ #Assumes the last line is a prompt
147
+ prompt = lines.pop
148
+ lines.each {|line| display line if line != cmd}
149
+ rescue TimeoutError
150
+ display "Timed out sending command to server.".red
151
+ rescue EOFError
152
+ err "The console connection has been terminated. Perhaps the app was stopped or deleted?"
153
+ end
154
+ prompt
155
+ end
156
+
157
+ def initialize_readline
158
+ if Readline.respond_to?("basic_word_break_characters=")
159
+ Readline.basic_word_break_characters= " \t\n`><=;|&{("
160
+ end
161
+ Readline.completion_append_character = nil
162
+ #Assumes that sending a String ending with tab will return a non-empty
163
+ #String of comma-separated completion options, terminated by a new line
164
+ #For example, "app.\t" might result in "to_s,nil?,etc\n"
165
+ Readline.completion_proc = proc {|s|
166
+ console_tab_completion_data s
167
+ }
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,122 @@
1
+ module JDCExtensions
2
+
3
+ def say(message)
4
+ JDC::Cli::Config.output.puts(message) if JDC::Cli::Config.output
5
+ end
6
+
7
+ def header(message, filler = '-')
8
+ say "\n"
9
+ say message
10
+ say filler.to_s * message.size
11
+ end
12
+
13
+ def banner(message)
14
+ say "\n"
15
+ say message
16
+ end
17
+
18
+ def display(message, nl=true)
19
+ if nl
20
+ say message
21
+ else
22
+ if JDC::Cli::Config.output
23
+ JDC::Cli::Config.output.print(message)
24
+ JDC::Cli::Config.output.flush
25
+ end
26
+ end
27
+ end
28
+
29
+ def clear(size=80)
30
+ return unless JDC::Cli::Config.output
31
+ JDC::Cli::Config.output.print("\r")
32
+ JDC::Cli::Config.output.print(" " * size)
33
+ JDC::Cli::Config.output.print("\r")
34
+ #JDC::Cli::Config.output.flush
35
+ end
36
+
37
+ def err(message, prefix='Error: ')
38
+ raise JDC::Cli::CliExit, "#{prefix}#{message}"
39
+ end
40
+
41
+ def warn(msg)
42
+ say "#{"[WARNING]".yellow} #{msg}"
43
+ end
44
+
45
+ def quit(message = nil)
46
+ raise JDC::Cli::GracefulExit, message
47
+ end
48
+
49
+ def blank?
50
+ self.to_s.blank?
51
+ end
52
+
53
+ def uptime_string(delta)
54
+ num_seconds = delta.to_i
55
+ days = num_seconds / (60 * 60 * 24);
56
+ num_seconds -= days * (60 * 60 * 24);
57
+ hours = num_seconds / (60 * 60);
58
+ num_seconds -= hours * (60 * 60);
59
+ minutes = num_seconds / 60;
60
+ num_seconds -= minutes * 60;
61
+ "#{days}d:#{hours}h:#{minutes}m:#{num_seconds}s"
62
+ end
63
+
64
+ def pretty_size(size, prec=1)
65
+ return 'NA' unless size
66
+ return "#{size}B" if size < 1024
67
+ return sprintf("%.#{prec}fK", size/1024.0) if size < (1024*1024)
68
+ return sprintf("%.#{prec}fM", size/(1024.0*1024.0)) if size < (1024*1024*1024)
69
+ return sprintf("%.#{prec}fG", size/(1024.0*1024.0*1024.0))
70
+ end
71
+ end
72
+
73
+ module JDCStringExtensions
74
+
75
+ def red
76
+ colorize("\e[0m\e[31m")
77
+ end
78
+
79
+ def green
80
+ colorize("\e[0m\e[32m")
81
+ end
82
+
83
+ def yellow
84
+ colorize("\e[0m\e[33m")
85
+ end
86
+
87
+ def bold
88
+ colorize("\e[0m\e[1m")
89
+ end
90
+
91
+ def colorize(color_code)
92
+ if JDC::Cli::Config.colorize
93
+ "#{color_code}#{self}\e[0m"
94
+ else
95
+ self
96
+ end
97
+ end
98
+
99
+ def blank?
100
+ self =~ /^\s*$/
101
+ end
102
+
103
+ def truncate(limit = 30)
104
+ return "" if self.blank?
105
+ etc = "..."
106
+ stripped = self.strip[0..limit]
107
+ if stripped.length > limit
108
+ stripped.gsub(/\s+?(\S+)?$/, "") + etc
109
+ else
110
+ stripped
111
+ end
112
+ end
113
+
114
+ end
115
+
116
+ class Object
117
+ include JDCExtensions
118
+ end
119
+
120
+ class String
121
+ include JDCStringExtensions
122
+ end
data/lib/cli/errors.rb ADDED
@@ -0,0 +1,19 @@
1
+ module JDC::Cli
2
+
3
+ class CliError < StandardError
4
+ def self.error_code(code = nil)
5
+ define_method(:error_code) { code }
6
+ end
7
+ end
8
+
9
+ class UnknownCommand < CliError; error_code(100); end
10
+ class TargetMissing < CliError; error_code(102); end
11
+ class TargetInaccessible < CliError; error_code(103); end
12
+
13
+ class TargetError < CliError; error_code(201); end
14
+ class AuthError < TargetError; error_code(202); end
15
+
16
+ class CliExit < CliError; error_code(400); end
17
+ class GracefulExit < CliExit; error_code(401); end
18
+
19
+ end