jdc 0.2.1 → 0.2.2.pre

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 +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.rb +15 -2
  16. data/lib/jdc/cli.rb +556 -0
  17. data/lib/jdc/cli/app/app.rb +43 -0
  18. data/lib/jdc/cli/app/apps.rb +87 -0
  19. data/lib/jdc/cli/app/base.rb +72 -0
  20. data/lib/jdc/cli/app/delete.rb +95 -0
  21. data/lib/jdc/cli/app/deprecated.rb +11 -0
  22. data/lib/jdc/cli/app/env.rb +78 -0
  23. data/lib/jdc/cli/app/events.rb +45 -0
  24. data/lib/jdc/cli/app/files.rb +137 -0
  25. data/lib/jdc/cli/app/health.rb +26 -0
  26. data/lib/jdc/cli/app/instances.rb +53 -0
  27. data/lib/jdc/cli/app/logs.rb +76 -0
  28. data/lib/jdc/cli/app/push.rb +103 -0
  29. data/lib/jdc/cli/app/push/create.rb +108 -0
  30. data/lib/jdc/cli/app/push/interactions.rb +86 -0
  31. data/lib/jdc/cli/app/push/sync.rb +57 -0
  32. data/lib/jdc/cli/app/rename.rb +35 -0
  33. data/lib/jdc/cli/app/restart.rb +31 -0
  34. data/lib/jdc/cli/app/scale.rb +63 -0
  35. data/lib/jdc/cli/app/start.rb +161 -0
  36. data/lib/jdc/cli/app/stats.rb +67 -0
  37. data/lib/jdc/cli/app/stop.rb +27 -0
  38. data/lib/jdc/cli/domain/base.rb +9 -0
  39. data/lib/jdc/cli/domain/domains.rb +40 -0
  40. data/lib/jdc/cli/domain/map.rb +55 -0
  41. data/lib/jdc/cli/domain/unmap.rb +56 -0
  42. data/lib/jdc/cli/help.rb +15 -0
  43. data/lib/jdc/cli/interactive.rb +105 -0
  44. data/lib/jdc/cli/login_requirements.rb +15 -0
  45. data/lib/jdc/cli/organization/base.rb +14 -0
  46. data/lib/jdc/cli/organization/create.rb +37 -0
  47. data/lib/jdc/cli/organization/delete.rb +63 -0
  48. data/lib/jdc/cli/organization/org.rb +45 -0
  49. data/lib/jdc/cli/organization/orgs.rb +30 -0
  50. data/lib/jdc/cli/organization/rename.rb +37 -0
  51. data/lib/jdc/cli/populators/base.rb +16 -0
  52. data/lib/jdc/cli/populators/organization.rb +32 -0
  53. data/lib/jdc/cli/populators/populator_methods.rb +64 -0
  54. data/lib/jdc/cli/populators/space.rb +33 -0
  55. data/lib/jdc/cli/populators/target.rb +13 -0
  56. data/lib/jdc/cli/route/base.rb +9 -0
  57. data/lib/jdc/cli/route/delete.rb +28 -0
  58. data/lib/jdc/cli/route/map.rb +68 -0
  59. data/lib/jdc/cli/route/routes.rb +26 -0
  60. data/lib/jdc/cli/route/unmap.rb +56 -0
  61. data/lib/jdc/cli/service/base.rb +9 -0
  62. data/lib/jdc/cli/service/bind.rb +44 -0
  63. data/lib/jdc/cli/service/create.rb +159 -0
  64. data/lib/jdc/cli/service/delete.rb +83 -0
  65. data/lib/jdc/cli/service/rename.rb +36 -0
  66. data/lib/jdc/cli/service/service.rb +42 -0
  67. data/lib/jdc/cli/service/service_instance_helper.rb +99 -0
  68. data/lib/jdc/cli/service/services.rb +111 -0
  69. data/lib/jdc/cli/service/unbind.rb +37 -0
  70. data/lib/jdc/cli/space/base.rb +29 -0
  71. data/lib/jdc/cli/space/create.rb +67 -0
  72. data/lib/jdc/cli/space/delete.rb +56 -0
  73. data/lib/jdc/cli/space/rename.rb +38 -0
  74. data/lib/jdc/cli/space/space.rb +66 -0
  75. data/lib/jdc/cli/space/spaces.rb +57 -0
  76. data/lib/jdc/cli/space/switch.rb +19 -0
  77. data/lib/jdc/cli/start/base.rb +41 -0
  78. data/lib/jdc/cli/start/colors.rb +13 -0
  79. data/lib/jdc/cli/start/target.rb +50 -0
  80. data/lib/jdc/cli/start/target_prettifier.rb +17 -0
  81. data/lib/jdc/cli/start/targets.rb +16 -0
  82. data/lib/jdc/cli/user/base.rb +30 -0
  83. data/lib/jdc/cli/user/create.rb +52 -0
  84. data/lib/jdc/cli/user/passwd.rb +37 -0
  85. data/lib/jdc/cli/user/register.rb +43 -0
  86. data/lib/jdc/cli/user/users.rb +32 -0
  87. data/lib/jdc/constants.rb +11 -0
  88. data/lib/jdc/errors.rb +19 -0
  89. data/lib/jdc/object_extensions.rb +15 -0
  90. data/lib/jdc/plugin.rb +56 -0
  91. data/lib/jdc/spacing.rb +89 -0
  92. data/lib/jdc/spec_helper.rb +1 -0
  93. data/lib/jdc/test_support.rb +6 -0
  94. data/lib/jdc/version.rb +3 -0
  95. data/lib/manifests/errors.rb +35 -0
  96. data/lib/manifests/loader.rb +31 -0
  97. data/lib/manifests/loader/builder.rb +39 -0
  98. data/lib/manifests/loader/normalizer.rb +145 -0
  99. data/lib/manifests/loader/resolver.rb +79 -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 +371 -210
  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.rb +0 -53
  125. data/lib/cli/commands/admin.rb +0 -58
  126. data/lib/cli/commands/apps.rb +0 -1129
  127. data/lib/cli/commands/base.rb +0 -228
  128. data/lib/cli/commands/manifest.rb +0 -56
  129. data/lib/cli/commands/micro.rb +0 -115
  130. data/lib/cli/commands/misc.rb +0 -126
  131. data/lib/cli/commands/services.rb +0 -178
  132. data/lib/cli/commands/user.rb +0 -14
  133. data/lib/cli/config.rb +0 -173
  134. data/lib/cli/console_helper.rb +0 -170
  135. data/lib/cli/core_ext.rb +0 -122
  136. data/lib/cli/errors.rb +0 -19
  137. data/lib/cli/frameworks.rb +0 -265
  138. data/lib/cli/manifest_helper.rb +0 -300
  139. data/lib/cli/runner.rb +0 -505
  140. data/lib/cli/services_helper.rb +0 -84
  141. data/lib/cli/tunnel_helper.rb +0 -332
  142. data/lib/cli/usage.rb +0 -86
  143. data/lib/cli/version.rb +0 -7
  144. data/lib/cli/zip_util.rb +0 -77
  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
@@ -1,178 +0,0 @@
1
- require "uuidtools"
2
-
3
- module JDC::Cli::Command
4
-
5
- class Services < Base
6
- include JDC::Cli::ServicesHelper
7
- include JDC::Cli::TunnelHelper
8
-
9
- def services
10
- ss = client.services_info
11
- ps = client.services
12
- ps.sort! {|a, b| a[:name] <=> b[:name] }
13
-
14
- if @options[:json]
15
- services = { :system => ss, :provisioned => ps }
16
- return display JSON.pretty_generate(services)
17
- end
18
- display_system_services(ss)
19
- display_provisioned_services(ps)
20
- end
21
-
22
- def create_service(service=nil, name=nil, appname=nil)
23
- unless no_prompt || service
24
- services = client.services_info
25
- err 'No services available to provision' if services.empty?
26
- service = ask(
27
- "Which service would you like to provision?",
28
- { :indexed => true,
29
- :choices =>
30
- services.values.collect { |type|
31
- type.keys.collect(&:to_s)
32
- }.flatten
33
- }
34
- )
35
- end
36
- name = @options[:name] unless name
37
- unless name
38
- name = random_service_name(service)
39
- picked_name = true
40
- end
41
- create_service_banner(service, name, picked_name)
42
- appname = @options[:bind] unless appname
43
- bind_service_banner(name, appname) if appname
44
- end
45
-
46
- def delete_service(service=nil)
47
- unless no_prompt || service
48
- user_services = client.services
49
- err 'No services available to delete' if user_services.empty?
50
- service = ask(
51
- "Which service would you like to delete?",
52
- { :indexed => true,
53
- :choices => user_services.collect { |s| s[:name] }
54
- }
55
- )
56
- end
57
- err "Service name required." unless service
58
- display "Deleting service [#{service}]: ", false
59
- client.delete_service(service)
60
- display 'OK'.green
61
- end
62
-
63
- def bind_service(service, appname)
64
- bind_service_banner(service, appname)
65
- end
66
-
67
- def unbind_service(service, appname)
68
- unbind_service_banner(service, appname)
69
- end
70
-
71
- def clone_services(src_app, dest_app)
72
- begin
73
- src = client.app_info(src_app)
74
- dest = client.app_info(dest_app)
75
- rescue
76
- end
77
-
78
- err "Application '#{src_app}' does not exist" unless src
79
- err "Application '#{dest_app}' does not exist" unless dest
80
-
81
- services = src[:services]
82
- err 'No services to clone' unless services && !services.empty?
83
- services.each { |service| bind_service_banner(service, dest_app, false) }
84
- check_app_for_restart(dest_app)
85
- end
86
-
87
- def tunnel(service=nil, client_name=nil)
88
- unless defined? Caldecott
89
- display "To use `jdc tunnel', you must first install Caldecott:"
90
- display ""
91
- display "\tgem install caldecott"
92
- display ""
93
- display "Note that you'll need a C compiler. If you're on OS X, Xcode"
94
- display "will provide one. If you're on Windows, try DevKit."
95
- display ""
96
- display "This manual step will be removed in the future."
97
- display ""
98
- err "Caldecott is not installed."
99
- end
100
-
101
- ps = client.services
102
- err "No services available to tunnel to" if ps.empty?
103
-
104
- unless service
105
- choices = ps.collect { |s| s[:name] }.sort
106
- service = ask(
107
- "Which service to tunnel to?",
108
- :choices => choices,
109
- :indexed => true
110
- )
111
- end
112
-
113
- info = ps.select { |s| s[:name] == service }.first
114
-
115
- err "Unknown service '#{service}'" unless info
116
-
117
- port = pick_tunnel_port(@options[:port] || 10000)
118
-
119
- if not tunnel_pushed?
120
- display "Deploying tunnel application '#{tunnel_appname}'."
121
- auth = UUIDTools::UUID.random_create.to_s
122
- push_caldecott(auth)
123
- bind_service_banner(service, tunnel_appname, false)
124
- start_caldecott
125
- else
126
- auth = tunnel_auth
127
- end
128
-
129
- if not tunnel_healthy?(auth)
130
- display "Redeploying tunnel application '#{tunnel_appname}'."
131
-
132
- # We don't expect caldecott not to be running, so take the
133
- # most aggressive restart method.. delete/re-push
134
- client.delete_app(tunnel_appname)
135
- invalidate_tunnel_app_info
136
-
137
- push_caldecott(auth)
138
- bind_service_banner(service, tunnel_appname, false)
139
- start_caldecott
140
- end
141
-
142
- if not tunnel_bound?(service)
143
- bind_service_banner(service, tunnel_appname)
144
- end
145
-
146
- conn_info = tunnel_connection_info info[:vendor], service, auth
147
- display_tunnel_connection_info(conn_info)
148
- display "Starting tunnel to #{service.bold} on port #{port.to_s.bold}."
149
- start_tunnel(port, conn_info, auth)
150
-
151
- clients = get_clients_for(info[:vendor])
152
-
153
- if clients.empty?
154
- client_name ||= "none"
155
- else
156
- client_name ||= ask(
157
- "Which client would you like to start?",
158
- :choices => ["none"] + clients.keys,
159
- :indexed => true
160
- )
161
- end
162
-
163
- if client_name == "none"
164
- wait_for_tunnel_end
165
- else
166
- wait_for_tunnel_start(port)
167
- unless start_local_prog(clients, client_name, conn_info, port)
168
- err "'#{client_name}' execution failed; is it in your $PATH?"
169
- end
170
- end
171
- end
172
-
173
- def get_clients_for(type)
174
- conf = JDC::Cli::Config.clients
175
- conf[type] || {}
176
- end
177
- end
178
- end
@@ -1,14 +0,0 @@
1
- module JDC::Cli::Command
2
-
3
- class User < Base
4
-
5
- def info
6
- info = client_info
7
- username = info[:user] || 'N/A'
8
- return display JSON.pretty_generate([username]) if @options[:json]
9
- display "\n[#{username}]"
10
- end
11
-
12
- end
13
-
14
- end
data/lib/cli/config.rb DELETED
@@ -1,173 +0,0 @@
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
@@ -1,170 +0,0 @@
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