vmc-tsuru 0.1.alpha

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,262 @@
1
+ require "set"
2
+
3
+ module VMC::Cli::ManifestHelper
4
+ include VMC::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
+ url_template = manifest("url") || DEFAULTS["url"]
86
+ url_resolved = url_template.dup
87
+ resolve_lexically(url_resolved)
88
+
89
+ # url = ask("Application Deployed URL", :default => url_resolved)
90
+
91
+ # url = url_template if url == url_resolved
92
+
93
+ # common error case is for prompted users to answer y or Y or yes or
94
+ # YES to this ask() resulting in an unintended URL of y. Special
95
+ # case this common error
96
+ url = DEFAULTS["url"] if YES_SET.member? url
97
+
98
+ set url, "url"
99
+
100
+ unless manifest "framework"
101
+ framework = detect_framework
102
+ set framework.name, "framework", "name"
103
+ set(
104
+ { "mem" => framework.mem,
105
+ "description" => framework.description,
106
+ "exec" => framework.exec
107
+ },
108
+ "framework",
109
+ "info"
110
+ )
111
+ end
112
+
113
+ # set ask(
114
+ # "Memory reservation",
115
+ # :default =>
116
+ # manifest("mem") ||
117
+ # manifest("framework", "info", "mem") ||
118
+ # DEFAULTS["mem"],
119
+ # :choices => ["128M", "256M", "512M", "1G", "2G"]
120
+ # ), "mem"
121
+
122
+ # set ask(
123
+ # "How many instances?",
124
+ # :default => manifest("instances") || DEFAULTS["instances"]
125
+ # ), "instances"
126
+
127
+ # unless manifest "services"
128
+ # user_services = client.services
129
+ # user_services.sort! {|a, b| a[:name] <=> b[:name] }
130
+
131
+ # unless user_services.empty?
132
+ # if ask "Bind existing services to '#{name}'?", :default => false
133
+ # bind_services(user_services)
134
+ # end
135
+ # end
136
+
137
+ # services = client.services_info
138
+ # unless services.empty?
139
+ # if ask "Create services to bind to '#{name}'?", :default => false
140
+ # create_services(services.values.collect(&:keys).flatten)
141
+ # end
142
+ # end
143
+ # end
144
+
145
+ # if many and ask("Configure for another application?", :default => false)
146
+ # @application = ask "Application path?"
147
+ # configure_app
148
+ # end
149
+ end
150
+
151
+ def set(what, *where)
152
+ where.unshift "applications", @application
153
+
154
+ which = @manifest
155
+ where.each_with_index do |k, i|
156
+ if i + 1 == where.size
157
+ which[k] = what
158
+ else
159
+ which = (which[k] ||= {})
160
+ end
161
+ end
162
+
163
+ what
164
+ end
165
+
166
+ # Detect the appropriate framework.
167
+ def detect_framework(prompt_ok = true)
168
+ framework = VMC::Cli::Framework.detect(@application)
169
+ framework_correct = ask("Detected a #{framework}, is this correct?", :default => true) if prompt_ok && framework
170
+ if prompt_ok && (framework.nil? || !framework_correct)
171
+ display "#{"[WARNING]".yellow} Can't determine the Application Type." unless framework
172
+ framework = nil if !framework_correct
173
+ framework = VMC::Cli::Framework.lookup(
174
+ ask(
175
+ "Select Application Type",
176
+ :indexed => true,
177
+ :default => framework,
178
+ :choices => VMC::Cli::Framework.known_frameworks
179
+ )
180
+ )
181
+ display "Selected #{framework}"
182
+ end
183
+
184
+ framework
185
+ end
186
+
187
+ def bind_services(user_services, chosen = 0)
188
+ svcname = ask(
189
+ "Which one?",
190
+ :indexed => true,
191
+ :choices => user_services.collect { |p| p[:name] })
192
+
193
+ svc = user_services.find { |p| p[:name] == svcname }
194
+
195
+ set svc[:vendor], "services", svcname, "type"
196
+
197
+ if chosen + 1 < user_services.size && ask("Bind another?", :default => false)
198
+ bind_services(user_services, chosen + 1)
199
+ end
200
+ end
201
+
202
+ def create_services(services)
203
+ svcs = services.collect(&:to_s).sort!
204
+
205
+ configure_service(
206
+ ask(
207
+ "What kind of service?",
208
+ :indexed => true,
209
+ :choices => svcs
210
+ )
211
+ )
212
+
213
+ if ask "Create another?", :default => false
214
+ create_services(services)
215
+ end
216
+ end
217
+
218
+ def configure_service(vendor)
219
+ default_name = random_service_name(vendor)
220
+ name = ask "Specify the name of the service", :default => default_name
221
+
222
+ set vendor, "services", name, "type"
223
+ end
224
+
225
+ private
226
+ def ordered_by_deps(apps, abspaths = nil, processed = Set[])
227
+ unless abspaths
228
+ abspaths = {}
229
+ apps.each do |p, i|
230
+ ep = File.expand_path("../" + p, manifest_file)
231
+ abspaths[ep] = i
232
+ end
233
+ end
234
+
235
+ ordered = []
236
+ apps.each do |path, info|
237
+ epath = File.expand_path("../" + path, manifest_file)
238
+
239
+ if deps = info["depends-on"]
240
+ dep_apps = {}
241
+ deps.each do |dep|
242
+ edep = File.expand_path("../" + dep, manifest_file)
243
+
244
+ err "Circular dependency detected." if processed.include? edep
245
+
246
+ dep_apps[dep] = abspaths[edep]
247
+ end
248
+
249
+ processed.add(epath)
250
+
251
+ ordered += ordered_by_deps(dep_apps, abspaths, processed)
252
+ ordered << [path, info]
253
+ elsif not processed.include? epath
254
+ ordered << [path, info]
255
+ processed.add(epath)
256
+ end
257
+ end
258
+
259
+ ordered
260
+ end
261
+
262
+ end