jdc 0.1.1
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.
- data/LICENSE +24 -0
- data/README.md +102 -0
- data/bin/jdc +6 -0
- data/caldecott_helper/server.rb +43 -0
- data/config/clients.yml +17 -0
- data/config/micro/paths.yml +22 -0
- data/config/micro/refresh_ip.rb +20 -0
- data/lib/cli/commands/admin.rb +58 -0
- data/lib/cli/commands/apps.rb +1128 -0
- data/lib/cli/commands/base.rb +228 -0
- data/lib/cli/commands/manifest.rb +56 -0
- data/lib/cli/commands/micro.rb +115 -0
- data/lib/cli/commands/misc.rb +126 -0
- data/lib/cli/commands/services.rb +178 -0
- data/lib/cli/commands/user.rb +14 -0
- data/lib/cli/config.rb +173 -0
- data/lib/cli/console_helper.rb +170 -0
- data/lib/cli/core_ext.rb +122 -0
- data/lib/cli/errors.rb +19 -0
- data/lib/cli/frameworks.rb +265 -0
- data/lib/cli/manifest_helper.rb +302 -0
- data/lib/cli/runner.rb +505 -0
- data/lib/cli/services_helper.rb +84 -0
- data/lib/cli/tunnel_helper.rb +332 -0
- data/lib/cli/usage.rb +86 -0
- data/lib/cli/version.rb +7 -0
- data/lib/cli/zip_util.rb +77 -0
- data/lib/cli.rb +53 -0
- data/lib/jdc/client.rb +457 -0
- data/lib/jdc/const.rb +25 -0
- data/lib/jdc/micro/switcher/base.rb +97 -0
- data/lib/jdc/micro/switcher/darwin.rb +19 -0
- data/lib/jdc/micro/switcher/dummy.rb +15 -0
- data/lib/jdc/micro/switcher/linux.rb +16 -0
- data/lib/jdc/micro/switcher/windows.rb +31 -0
- data/lib/jdc/micro/vmrun.rb +168 -0
- data/lib/jdc/micro.rb +56 -0
- data/lib/jdc/signature/version.rb +27 -0
- data/lib/jdc/signer.rb +13 -0
- data/lib/jdc/timer.rb +12 -0
- data/lib/jdc.rb +3 -0
- metadata +175 -0
@@ -0,0 +1,265 @@
|
|
1
|
+
module JDC::Cli
|
2
|
+
|
3
|
+
class Framework
|
4
|
+
|
5
|
+
DEFAULT_FRAMEWORK = "http://b20nine.com/unknown"
|
6
|
+
DEFAULT_MEM = '256M'
|
7
|
+
|
8
|
+
FRAMEWORKS = {
|
9
|
+
'Rails' => ['rails3', { :mem => '256M', :description => 'Rails Application', :console=>true}],
|
10
|
+
'Spring' => ['spring', { :mem => '512M', :description => 'Java SpringSource Spring Application'}],
|
11
|
+
'Grails' => ['grails', { :mem => '512M', :description => 'Java SpringSource Grails Application'}],
|
12
|
+
'Lift' => ['lift', { :mem => '512M', :description => 'Scala Lift Application'}],
|
13
|
+
'JavaWeb' => ['java_web',{ :mem => '512M', :description => 'Java Web Application'}],
|
14
|
+
'Standalone' => ['standalone', { :mem => '64M', :description => 'Standalone Application'}],
|
15
|
+
'Sinatra' => ['sinatra', { :mem => '128M', :description => 'Sinatra Application'}],
|
16
|
+
'Node' => ['node', { :mem => '64M', :description => 'Node.js Application'}],
|
17
|
+
'PHP' => ['php', { :mem => '128M', :description => 'PHP Application'}],
|
18
|
+
'Erlang/OTP Rebar' => ['otp_rebar', { :mem => '64M', :description => 'Erlang/OTP Rebar Application'}],
|
19
|
+
'WSGI' => ['wsgi', { :mem => '64M', :description => 'Python WSGI Application'}],
|
20
|
+
'Django' => ['django', { :mem => '128M', :description => 'Python Django Application'}],
|
21
|
+
'dotNet' => ['dotNet', { :mem => '128M', :description => '.Net Web Application'}],
|
22
|
+
'Rack' => ['rack', { :mem => '128M', :description => 'Rack Application'}],
|
23
|
+
'Play' => ['play', { :mem => '256M', :description => 'Play Framework Application'}]
|
24
|
+
}
|
25
|
+
|
26
|
+
class << self
|
27
|
+
|
28
|
+
def known_frameworks(available_frameworks)
|
29
|
+
frameworks = []
|
30
|
+
FRAMEWORKS.each do |key,fw|
|
31
|
+
frameworks << key if available_frameworks.include? [fw[0]]
|
32
|
+
end
|
33
|
+
frameworks
|
34
|
+
end
|
35
|
+
|
36
|
+
def lookup(name)
|
37
|
+
return create(*FRAMEWORKS[name])
|
38
|
+
end
|
39
|
+
|
40
|
+
def lookup_by_framework(name)
|
41
|
+
FRAMEWORKS.each do |key,fw|
|
42
|
+
return create(fw[0],fw[1]) if fw[0] == name
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def create(name,opts)
|
47
|
+
if name == "standalone"
|
48
|
+
return StandaloneFramework.new(name, opts)
|
49
|
+
else
|
50
|
+
return Framework.new(name,opts)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def detect(path, available_frameworks)
|
55
|
+
if !File.directory? path
|
56
|
+
if path.end_with?('.war')
|
57
|
+
return detect_framework_from_war path
|
58
|
+
elsif path.end_with?('.zip')
|
59
|
+
return detect_framework_from_zip path, available_frameworks
|
60
|
+
elsif available_frameworks.include?(["standalone"])
|
61
|
+
return Framework.lookup('Standalone')
|
62
|
+
else
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
end
|
66
|
+
Dir.chdir(path) do
|
67
|
+
# Rails
|
68
|
+
if File.exist?('config/environment.rb')
|
69
|
+
return Framework.lookup('Rails')
|
70
|
+
|
71
|
+
# Rack
|
72
|
+
elsif File.exist?('config.ru') && available_frameworks.include?(["rack"])
|
73
|
+
return Framework.lookup('Rack')
|
74
|
+
|
75
|
+
# Java Web Apps
|
76
|
+
elsif Dir.glob('*.war').first
|
77
|
+
return detect_framework_from_war(Dir.glob('*.war').first)
|
78
|
+
|
79
|
+
elsif File.exist?('WEB-INF/web.xml')
|
80
|
+
return detect_framework_from_war
|
81
|
+
|
82
|
+
# Simple Ruby Apps
|
83
|
+
elsif !Dir.glob('*.rb').empty?
|
84
|
+
matched_file = nil
|
85
|
+
Dir.glob('*.rb').each do |fname|
|
86
|
+
next if matched_file
|
87
|
+
File.open(fname, 'r') do |f|
|
88
|
+
str = f.read # This might want to be limited
|
89
|
+
matched_file = fname if (str && str.match(/^\s*require[\s\(]*['"]sinatra(\/base)?['"]/))
|
90
|
+
end
|
91
|
+
end
|
92
|
+
if matched_file
|
93
|
+
# Sinatra apps
|
94
|
+
f = Framework.lookup('Sinatra')
|
95
|
+
f.exec = "ruby #{matched_file}"
|
96
|
+
return f
|
97
|
+
end
|
98
|
+
|
99
|
+
# PHP
|
100
|
+
elsif !Dir.glob('*.php').empty?
|
101
|
+
return Framework.lookup('PHP')
|
102
|
+
|
103
|
+
# Erlang/OTP using Rebar
|
104
|
+
elsif !Dir.glob('releases/*/*.rel').empty? && !Dir.glob('releases/*/*.boot').empty?
|
105
|
+
return Framework.lookup('Erlang/OTP Rebar')
|
106
|
+
|
107
|
+
# Python Django
|
108
|
+
# XXX: not all django projects keep settings.py in top-level directory
|
109
|
+
elsif File.exist?('manage.py') && File.exist?('settings.py')
|
110
|
+
return Framework.lookup('Django')
|
111
|
+
|
112
|
+
# Python
|
113
|
+
elsif !Dir.glob('wsgi.py').empty?
|
114
|
+
return Framework.lookup('WSGI')
|
115
|
+
|
116
|
+
# .Net
|
117
|
+
elsif !Dir.glob('web.config').empty?
|
118
|
+
return Framework.lookup('dotNet')
|
119
|
+
|
120
|
+
# Node.js
|
121
|
+
elsif !Dir.glob('*.js').empty?
|
122
|
+
if File.exist?('server.js') || File.exist?('app.js') || File.exist?('index.js') || File.exist?('main.js')
|
123
|
+
return Framework.lookup('Node')
|
124
|
+
end
|
125
|
+
|
126
|
+
# Play or Standalone Apps
|
127
|
+
elsif Dir.glob('*.zip').first
|
128
|
+
zip_file = Dir.glob('*.zip').first
|
129
|
+
return detect_framework_from_zip zip_file, available_frameworks
|
130
|
+
end
|
131
|
+
|
132
|
+
# Default to Standalone if no other match was made
|
133
|
+
return Framework.lookup('Standalone') if available_frameworks.include?(["standalone"])
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def detect_framework_from_war(war_file=nil)
|
138
|
+
if war_file
|
139
|
+
contents = ZipUtil.entry_lines(war_file)
|
140
|
+
else
|
141
|
+
#assume we are working with current dir
|
142
|
+
contents = Dir['**/*'].join("\n")
|
143
|
+
end
|
144
|
+
|
145
|
+
# Spring/Lift Variations
|
146
|
+
if contents =~ /WEB-INF\/lib\/grails-web.*\.jar/
|
147
|
+
return Framework.lookup('Grails')
|
148
|
+
elsif contents =~ /WEB-INF\/lib\/lift-webkit.*\.jar/
|
149
|
+
return Framework.lookup('Lift')
|
150
|
+
elsif contents =~ /WEB-INF\/classes\/org\/springframework/
|
151
|
+
return Framework.lookup('Spring')
|
152
|
+
elsif contents =~ /WEB-INF\/lib\/spring-core.*\.jar/
|
153
|
+
return Framework.lookup('Spring')
|
154
|
+
elsif contents =~ /WEB-INF\/lib\/org\.springframework\.core.*\.jar/
|
155
|
+
return Framework.lookup('Spring')
|
156
|
+
else
|
157
|
+
return Framework.lookup('JavaWeb')
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def detect_framework_from_zip(zip_file, available_frameworks)
|
162
|
+
contents = ZipUtil.entry_lines(zip_file)
|
163
|
+
detect_framework_from_zip_contents(contents, available_frameworks)
|
164
|
+
end
|
165
|
+
|
166
|
+
def detect_framework_from_zip_contents(contents, available_frameworks)
|
167
|
+
if available_frameworks.include?(["play"]) && contents =~ /lib\/play\..*\.jar/
|
168
|
+
return Framework.lookup('Play')
|
169
|
+
elsif available_frameworks.include?(["standalone"])
|
170
|
+
return Framework.lookup('Standalone')
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
attr_reader :name, :description, :console
|
176
|
+
attr_accessor :exec
|
177
|
+
|
178
|
+
def initialize(framework=nil, opts={})
|
179
|
+
@name = framework || DEFAULT_FRAMEWORK
|
180
|
+
@memory = opts[:mem] || DEFAULT_MEM
|
181
|
+
@description = opts[:description] || 'Unknown Application Type'
|
182
|
+
@exec = opts[:exec]
|
183
|
+
@console = opts[:console] || false
|
184
|
+
end
|
185
|
+
|
186
|
+
def to_s
|
187
|
+
description
|
188
|
+
end
|
189
|
+
|
190
|
+
def require_url?
|
191
|
+
true
|
192
|
+
end
|
193
|
+
|
194
|
+
def require_start_command?
|
195
|
+
false
|
196
|
+
end
|
197
|
+
|
198
|
+
def prompt_for_runtime?
|
199
|
+
false
|
200
|
+
end
|
201
|
+
|
202
|
+
def default_runtime(path)
|
203
|
+
nil
|
204
|
+
end
|
205
|
+
|
206
|
+
def memory(runtime=nil)
|
207
|
+
@memory
|
208
|
+
end
|
209
|
+
|
210
|
+
alias :mem :memory
|
211
|
+
end
|
212
|
+
|
213
|
+
class StandaloneFramework < Framework
|
214
|
+
def require_url?
|
215
|
+
false
|
216
|
+
end
|
217
|
+
|
218
|
+
def require_start_command?
|
219
|
+
true
|
220
|
+
end
|
221
|
+
|
222
|
+
def prompt_for_runtime?
|
223
|
+
true
|
224
|
+
end
|
225
|
+
|
226
|
+
def default_runtime(path)
|
227
|
+
if !File.directory? path
|
228
|
+
if path =~ /\.(jar|class)$/
|
229
|
+
return "java"
|
230
|
+
elsif path =~ /\.(rb)$/
|
231
|
+
return "ruby18"
|
232
|
+
elsif path =~ /\.(zip)$/
|
233
|
+
return detect_runtime_from_zip path
|
234
|
+
end
|
235
|
+
else
|
236
|
+
Dir.chdir(path) do
|
237
|
+
return "ruby18" if not Dir.glob('**/*.rb').empty?
|
238
|
+
if !Dir.glob('**/*.class').empty? || !Dir.glob('**/*.jar').empty?
|
239
|
+
return "java"
|
240
|
+
elsif Dir.glob('*.zip').first
|
241
|
+
zip_file = Dir.glob('*.zip').first
|
242
|
+
return detect_runtime_from_zip zip_file
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
return nil
|
247
|
+
end
|
248
|
+
|
249
|
+
def memory(runtime=nil)
|
250
|
+
default_mem = @memory
|
251
|
+
default_mem = '128M' if runtime =~ /\Aruby/ || runtime == "php"
|
252
|
+
default_mem = '512M' if runtime == "java" || runtime == "java7"
|
253
|
+
default_mem
|
254
|
+
end
|
255
|
+
|
256
|
+
private
|
257
|
+
def detect_runtime_from_zip(zip_file)
|
258
|
+
contents = ZipUtil.entry_lines(zip_file)
|
259
|
+
if contents =~ /\.(jar)$/
|
260
|
+
return "java"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
@@ -0,0 +1,302 @@
|
|
1
|
+
require "set"
|
2
|
+
|
3
|
+
module JDC::Cli::ManifestHelper
|
4
|
+
include JDC::Cli::ServicesHelper
|
5
|
+
|
6
|
+
DEFAULTS = {
|
7
|
+
"url" => "${name}.${target-base}",
|
8
|
+
"mem" => "128M",
|
9
|
+
"instances" => 1
|
10
|
+
}
|
11
|
+
|
12
|
+
MANIFEST = "manifest.yml"
|
13
|
+
|
14
|
+
YES_SET = Set.new(["y", "Y", "yes", "YES"])
|
15
|
+
|
16
|
+
# take a block and call it once for each app to push/update.
|
17
|
+
# with @application and @app_info set appropriately
|
18
|
+
def each_app(panic=true)
|
19
|
+
if @manifest and all_apps = @manifest["applications"]
|
20
|
+
where = File.expand_path(@path)
|
21
|
+
single = false
|
22
|
+
|
23
|
+
all_apps.each do |path, info|
|
24
|
+
app = File.expand_path("../" + path, manifest_file)
|
25
|
+
if where.start_with?(app)
|
26
|
+
@application = app
|
27
|
+
@app_info = info
|
28
|
+
yield info["name"]
|
29
|
+
single = true
|
30
|
+
break
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
unless single
|
35
|
+
if where == File.expand_path("../", manifest_file)
|
36
|
+
ordered_by_deps(all_apps).each do |path, info|
|
37
|
+
app = File.expand_path("../" + path, manifest_file)
|
38
|
+
@application = app
|
39
|
+
@app_info = info
|
40
|
+
yield info["name"]
|
41
|
+
end
|
42
|
+
else
|
43
|
+
err "Path '#{@path}' is not known to manifest '#{manifest_file}'."
|
44
|
+
end
|
45
|
+
end
|
46
|
+
else
|
47
|
+
@application = @path
|
48
|
+
@app_info = @manifest
|
49
|
+
if @app_info
|
50
|
+
yield @app_info["name"]
|
51
|
+
elsif panic
|
52
|
+
err "No applications."
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
nil
|
57
|
+
ensure
|
58
|
+
@application = nil
|
59
|
+
@app_info = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def interact(many=false)
|
63
|
+
@manifest ||= {}
|
64
|
+
configure_app(many)
|
65
|
+
end
|
66
|
+
|
67
|
+
def target_manifest
|
68
|
+
@options[:manifest] || MANIFEST
|
69
|
+
end
|
70
|
+
|
71
|
+
def save_manifest(save_to = nil)
|
72
|
+
save_to ||= target_manifest
|
73
|
+
|
74
|
+
File.open(save_to, "w") do |f|
|
75
|
+
f.write @manifest.to_yaml
|
76
|
+
end
|
77
|
+
|
78
|
+
say "Manifest written to #{save_to}."
|
79
|
+
end
|
80
|
+
|
81
|
+
def configure_app(many=false)
|
82
|
+
name = manifest("name") ||
|
83
|
+
set(ask("Application Name", :default => manifest("name")), "name")
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
if manifest "framework"
|
88
|
+
framework = JDC::Cli::Framework.lookup_by_framework manifest("framework","name")
|
89
|
+
else
|
90
|
+
framework = detect_framework
|
91
|
+
set framework.name, "framework", "name"
|
92
|
+
set(
|
93
|
+
{ "mem" => framework.mem,
|
94
|
+
"description" => framework.description,
|
95
|
+
"exec" => framework.exec
|
96
|
+
},
|
97
|
+
"framework",
|
98
|
+
"info"
|
99
|
+
)
|
100
|
+
end
|
101
|
+
|
102
|
+
default_runtime = manifest "runtime"
|
103
|
+
if not default_runtime
|
104
|
+
default_runtime = framework.default_runtime(@application)
|
105
|
+
set(detect_runtime(default_runtime), "runtime") if framework.prompt_for_runtime?
|
106
|
+
end
|
107
|
+
default_command = manifest "command"
|
108
|
+
set ask("Start Command", :default => default_command), "command" if framework.require_start_command?
|
109
|
+
|
110
|
+
url_template = manifest("url") || DEFAULTS["url"]
|
111
|
+
url_resolved = url_template.dup
|
112
|
+
resolve_lexically(url_resolved)
|
113
|
+
|
114
|
+
if !framework.require_url?
|
115
|
+
url_resolved = "None"
|
116
|
+
end
|
117
|
+
url = ask("Application Deployed URL", :default => url_resolved)
|
118
|
+
|
119
|
+
if url == url_resolved && url != "None"
|
120
|
+
url = url_template
|
121
|
+
end
|
122
|
+
|
123
|
+
# common error case is for prompted users to answer y or Y or yes or
|
124
|
+
# YES to this ask() resulting in an unintended URL of y. Special
|
125
|
+
# case this common error
|
126
|
+
url = url_resolved if YES_SET.member? url
|
127
|
+
|
128
|
+
if(url == "None")
|
129
|
+
url = nil
|
130
|
+
end
|
131
|
+
|
132
|
+
set url, "url"
|
133
|
+
|
134
|
+
default_mem = manifest("mem")
|
135
|
+
default_mem = framework.memory(manifest("runtime")) if not default_mem
|
136
|
+
set ask(
|
137
|
+
"Memory reservation",
|
138
|
+
:default =>
|
139
|
+
default_mem ||
|
140
|
+
DEFAULTS["mem"],
|
141
|
+
:choices => ["128M", "256M", "512M", "1G", "2G"]
|
142
|
+
), "mem"
|
143
|
+
|
144
|
+
set ask(
|
145
|
+
"How many instances?",
|
146
|
+
:default => manifest("instances") || DEFAULTS["instances"]
|
147
|
+
), "instances"
|
148
|
+
|
149
|
+
unless manifest "services"
|
150
|
+
user_services = client.services
|
151
|
+
user_services.sort! {|a, b| a[:name] <=> b[:name] }
|
152
|
+
|
153
|
+
unless user_services.empty?
|
154
|
+
if ask "Bind existing services to '#{name}'?", :default => false
|
155
|
+
bind_services(user_services)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
services = client.services_info
|
160
|
+
unless services.empty?
|
161
|
+
if ask "Create services to bind to '#{name}'?", :default => false
|
162
|
+
create_services(services.values.collect(&:keys).flatten)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
if many and ask("Configure for another application?", :default => false)
|
168
|
+
@application = ask "Application path?"
|
169
|
+
configure_app
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def set(what, *where)
|
174
|
+
where.unshift "applications", @application
|
175
|
+
|
176
|
+
which = @manifest
|
177
|
+
where.each_with_index do |k, i|
|
178
|
+
if i + 1 == where.size
|
179
|
+
which[k] = what
|
180
|
+
else
|
181
|
+
which = (which[k] ||= {})
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
what
|
186
|
+
end
|
187
|
+
|
188
|
+
# Detect the appropriate framework.
|
189
|
+
def detect_framework(prompt_ok = true)
|
190
|
+
framework = JDC::Cli::Framework.detect(@application, frameworks_info)
|
191
|
+
framework_correct = ask("Detected a #{framework}, is this correct?", :default => true) if prompt_ok && framework
|
192
|
+
if prompt_ok && (framework.nil? || !framework_correct)
|
193
|
+
display "#{"[WARNING]".yellow} Can't determine the Application Type." unless framework
|
194
|
+
framework = nil if !framework_correct
|
195
|
+
framework = JDC::Cli::Framework.lookup(
|
196
|
+
ask(
|
197
|
+
"Select Application Type",
|
198
|
+
:indexed => true,
|
199
|
+
:default => framework,
|
200
|
+
:choices => JDC::Cli::Framework.known_frameworks(frameworks_info)
|
201
|
+
)
|
202
|
+
)
|
203
|
+
display "Selected #{framework}"
|
204
|
+
end
|
205
|
+
|
206
|
+
framework
|
207
|
+
end
|
208
|
+
|
209
|
+
# Detect the appropriate runtime.
|
210
|
+
def detect_runtime(default, prompt_ok=true)
|
211
|
+
runtime = nil
|
212
|
+
runtime_keys=[]
|
213
|
+
runtimes_info.keys.each {|runtime_key| runtime_keys << runtime_key.dup }
|
214
|
+
runtime_keys.sort!
|
215
|
+
if prompt_ok
|
216
|
+
runtime = ask(
|
217
|
+
"Select Runtime",
|
218
|
+
:indexed => true,
|
219
|
+
:default => default,
|
220
|
+
:choices => runtime_keys
|
221
|
+
)
|
222
|
+
display "Selected #{runtime}"
|
223
|
+
end
|
224
|
+
runtime
|
225
|
+
end
|
226
|
+
|
227
|
+
def bind_services(user_services, chosen = 0)
|
228
|
+
svcname = ask(
|
229
|
+
"Which one?",
|
230
|
+
:indexed => true,
|
231
|
+
:choices => user_services.collect { |p| p[:name] })
|
232
|
+
|
233
|
+
svc = user_services.find { |p| p[:name] == svcname }
|
234
|
+
|
235
|
+
set svc[:vendor], "services", svcname, "type"
|
236
|
+
|
237
|
+
if chosen + 1 < user_services.size && ask("Bind another?", :default => false)
|
238
|
+
bind_services(user_services, chosen + 1)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def create_services(services)
|
243
|
+
svcs = services.collect(&:to_s).sort!
|
244
|
+
|
245
|
+
configure_service(
|
246
|
+
ask(
|
247
|
+
"What kind of service?",
|
248
|
+
:indexed => true,
|
249
|
+
:choices => svcs
|
250
|
+
)
|
251
|
+
)
|
252
|
+
|
253
|
+
if ask "Create another?", :default => false
|
254
|
+
create_services(services)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
def configure_service(vendor)
|
259
|
+
default_name = random_service_name(vendor)
|
260
|
+
name = ask "Specify the name of the service", :default => default_name
|
261
|
+
|
262
|
+
set vendor, "services", name, "type"
|
263
|
+
end
|
264
|
+
|
265
|
+
private
|
266
|
+
def ordered_by_deps(apps, abspaths = nil, processed = Set[])
|
267
|
+
unless abspaths
|
268
|
+
abspaths = {}
|
269
|
+
apps.each do |p, i|
|
270
|
+
ep = File.expand_path("../" + p, manifest_file)
|
271
|
+
abspaths[ep] = i
|
272
|
+
end
|
273
|
+
end
|
274
|
+
|
275
|
+
ordered = []
|
276
|
+
apps.each do |path, info|
|
277
|
+
epath = File.expand_path("../" + path, manifest_file)
|
278
|
+
|
279
|
+
if deps = info["depends-on"]
|
280
|
+
dep_apps = {}
|
281
|
+
deps.each do |dep|
|
282
|
+
edep = File.expand_path("../" + dep, manifest_file)
|
283
|
+
|
284
|
+
err "Circular dependency detected." if processed.include? edep
|
285
|
+
|
286
|
+
dep_apps[dep] = abspaths[edep]
|
287
|
+
end
|
288
|
+
|
289
|
+
processed.add(epath)
|
290
|
+
|
291
|
+
ordered += ordered_by_deps(dep_apps, abspaths, processed)
|
292
|
+
ordered << [path, info]
|
293
|
+
elsif not processed.include? epath
|
294
|
+
ordered << [path, info]
|
295
|
+
processed.add(epath)
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
ordered
|
300
|
+
end
|
301
|
+
|
302
|
+
end
|