manifests-vmc-plugin 0.4.13 → 0.4.14

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,34 @@
1
+ module VMCManifests
2
+ module Builder
3
+ # parse a manifest and merge with its inherited manifests
4
+ def build(file)
5
+ manifest = YAML.load_file file
6
+
7
+ Array(manifest["inherit"]).each do |path|
8
+ manifest = merge_parent(path, manifest)
9
+ end
10
+
11
+ manifest
12
+ end
13
+
14
+ private
15
+
16
+ # merge the manifest at `parent_path' into the `child'
17
+ def merge_parent(parent_path, child)
18
+ merge_manifest(build(from_manifest(parent_path)), child)
19
+ end
20
+
21
+ # deep hash merge
22
+ def merge_manifest(parent, child)
23
+ merge = proc do |_, old, new|
24
+ if new.is_a?(Hash) && old.is_a?(Hash)
25
+ old.merge(new, &merge)
26
+ else
27
+ new
28
+ end
29
+ end
30
+
31
+ parent.merge(child, &merge)
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,112 @@
1
+ module VMCManifests
2
+ module Normalizer
3
+ MANIFEST_META = ["applications", "properties"]
4
+
5
+ def normalize!(manifest)
6
+ toplevel = toplevel_attributes(manifest)
7
+
8
+ apps = manifest["applications"]
9
+ apps ||= [{}]
10
+
11
+ default_paths_to_keys!(apps)
12
+
13
+ apps = convert_from_array(apps)
14
+
15
+ merge_toplevel!(toplevel, manifest, apps)
16
+ normalize_apps!(apps)
17
+
18
+ manifest["applications"] = apps
19
+
20
+ normalize_paths!(apps)
21
+
22
+ keyval = normalize_key_val(manifest)
23
+ manifest.clear.merge!(keyval)
24
+
25
+ nil
26
+ end
27
+
28
+ private
29
+
30
+ def normalize_paths!(apps)
31
+ apps.each do |_, app|
32
+ app["path"] = from_manifest(app["path"])
33
+ end
34
+ end
35
+
36
+ def convert_from_array(apps)
37
+ return apps unless apps.is_a?(Array)
38
+
39
+ apps_hash = {}
40
+ apps.each.with_index do |a, i|
41
+ apps_hash[i.to_s] = a
42
+ end
43
+
44
+ apps_hash
45
+ end
46
+
47
+ def default_paths_to_keys!(apps)
48
+ return if apps.is_a?(Array)
49
+
50
+ apps.each do |tag, app|
51
+ app["path"] ||= tag
52
+ end
53
+ end
54
+
55
+ def normalize_apps!(apps)
56
+ apps.each_value do |app|
57
+ normalize_app!(app)
58
+ end
59
+ end
60
+
61
+ def merge_toplevel!(toplevel, manifest, apps)
62
+ return if toplevel.empty?
63
+
64
+ apps.each do |t, a|
65
+ apps[t] = toplevel.merge(a)
66
+ end
67
+
68
+ toplevel.each do |k, _|
69
+ manifest.delete k
70
+ end
71
+ end
72
+
73
+ def normalize_app!(app)
74
+ if app["framework"].is_a?(Hash)
75
+ app["framework"] = app["framework"]["name"]
76
+ end
77
+
78
+ if app.key?("mem")
79
+ app["memory"] = app.delete("mem")
80
+ end
81
+ end
82
+
83
+ def toplevel_attributes(manifest)
84
+ top =
85
+ manifest.reject { |k, _|
86
+ MANIFEST_META.include? k
87
+ }
88
+
89
+ # implicit toplevel path of .
90
+ top["path"] ||= "."
91
+
92
+ top
93
+ end
94
+
95
+ def normalize_key_val(val)
96
+ case val
97
+ when Hash
98
+ stringified = {}
99
+
100
+ val.each do |k, v|
101
+ stringified[k.to_sym] = normalize_key_val(v)
102
+ end
103
+
104
+ stringified
105
+ when Array
106
+ val.collect { |x| normalize_key_val(x) }
107
+ else
108
+ val.to_s
109
+ end
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,75 @@
1
+ module VMCManifests
2
+ module Resolver
3
+ def resolve!(manifest, resolver)
4
+ manifest[:applications].each_value do |v|
5
+ resolve_lexically(resolver, v, [manifest])
6
+ end
7
+
8
+ resolve_lexically(resolver, manifest, [manifest])
9
+
10
+ nil
11
+ end
12
+
13
+ private
14
+
15
+ # resolve symbols, with hashes introducing new lexical symbols
16
+ def resolve_lexically(resolver, val, ctx)
17
+ case val
18
+ when Hash
19
+ val.each_value do |v|
20
+ resolve_lexically(resolver, v, [val] + ctx)
21
+ end
22
+ when Array
23
+ val.each do |v|
24
+ resolve_lexically(resolver, v, ctx)
25
+ end
26
+ when String
27
+ val.gsub!(/\$\{([^\}]+)\}/) do
28
+ resolve(resolver, $1, ctx)
29
+ end
30
+ end
31
+
32
+ nil
33
+ end
34
+
35
+ # resolve a symbol to its value, and then resolve that value
36
+ def resolve(resolver, sym, ctx)
37
+ if found = find_symbol(sym.to_sym, ctx)
38
+ resolve_lexically(resolver, found, ctx)
39
+ found
40
+ elsif dynamic = resolver.resolve_symbol(sym)
41
+ dynamic
42
+ else
43
+ fail("Unknown symbol in manifest: #{sym}")
44
+ end
45
+ end
46
+
47
+ # search for a symbol introduced in the lexical context
48
+ def find_symbol(sym, ctx)
49
+ ctx.each do |h|
50
+ if val = resolve_in(h, sym)
51
+ return val
52
+ end
53
+ end
54
+
55
+ nil
56
+ end
57
+
58
+ # find a value, searching in explicit properties first
59
+ def resolve_in(hash, *where)
60
+ find_in_hash(hash, [:properties] + where) ||
61
+ find_in_hash(hash, where)
62
+ end
63
+
64
+ # helper for following a path of values in a hash
65
+ def find_in_hash(hash, where)
66
+ what = hash
67
+ where.each do |x|
68
+ return nil unless what.is_a?(Hash)
69
+ what = what[x]
70
+ end
71
+
72
+ what
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,32 @@
1
+ require "manifests-vmc-plugin/loader/builder"
2
+ require "manifests-vmc-plugin/loader/normalizer"
3
+ require "manifests-vmc-plugin/loader/resolver"
4
+
5
+ module VMCManifests
6
+ class Loader
7
+ include Builder
8
+ include Normalizer
9
+ include Resolver
10
+
11
+ def initialize(file, resolver)
12
+ @file = file
13
+ @resolver = resolver
14
+ end
15
+
16
+ def manifest
17
+ info = build(@file)
18
+ normalize! info
19
+ resolve! info, @resolver
20
+ info
21
+ end
22
+
23
+ private
24
+
25
+ # expand a path relative to the manifest file's directory
26
+ def from_manifest(path)
27
+ return path unless @file
28
+
29
+ File.expand_path(path, File.dirname(@file))
30
+ end
31
+ end
32
+ end
@@ -4,29 +4,13 @@ require "vmc/plugin"
4
4
  require "manifests-vmc-plugin"
5
5
 
6
6
 
7
- class Manifests < VMC::CLI
7
+ class Manifests < VMC::App::Base
8
8
  include VMCManifests
9
9
 
10
- @@showed_manifest_usage = false
11
-
12
10
  option :manifest, :aliases => "-m", :value => :file,
13
11
  :desc => "Path to manifest file to use"
14
12
 
15
13
 
16
- def no_apps
17
- fail "No applications or manifest to operate on."
18
- end
19
-
20
- def show_manifest_usage
21
- return if @@showed_manifest_usage
22
-
23
- path = Pathname.new(manifest_file).relative_path_from(Pathname.pwd)
24
- line "Using manifest file #{c(path, :name)}"
25
- line
26
-
27
- @@showed_manifest_usage = true
28
- end
29
-
30
14
  # basic commands that, when given no name, act on the
31
15
  # app(s) described by the manifest, in dependency-order
32
16
  [ :start, :restart, :instances, :logs, :env,
@@ -104,17 +88,21 @@ class Manifests < VMC::CLI
104
88
  :desc => "Reset to values in the manifest"
105
89
 
106
90
  around(:push) do |push, input|
107
- single =
91
+ particular =
108
92
  if input.given?(:name)
109
93
  path = File.expand_path(input[:name])
110
94
  find_by = File.exists?(path) ? path : input[:name]
111
95
 
112
- app_info(find_by, input.without(:name))
96
+ find_apps(find_by)
97
+ else
98
+ []
113
99
  end
114
100
 
115
- single ||= app_info(Dir.pwd, input)
101
+ if particular.empty?
102
+ particular = find_apps(Dir.pwd)
103
+ end
116
104
 
117
- apps = single ? [single] : all_apps(input)
105
+ apps = particular.empty? ? all_apps : particular
118
106
 
119
107
  if apps.empty?
120
108
  with_filters(
@@ -127,7 +115,7 @@ class Manifests < VMC::CLI
127
115
  else
128
116
  show_manifest_usage
129
117
 
130
- apps.each do |app|
118
+ spaced(apps) do |app|
131
119
  with_filters(
132
120
  :push => {
133
121
  :create_app => proc { |a|
@@ -141,7 +129,7 @@ class Manifests < VMC::CLI
141
129
  }) do
142
130
  # only set inputs if creating app or updating with --reset
143
131
  if input[:reset] || !client.app_by_name(app[:name])
144
- app_input = input.merge_given(app)
132
+ app_input = input.rebase_given(app)
145
133
  else
146
134
  app_input = input.merge(:path => from_manifest(app[:path]))
147
135
  end
@@ -1,3 +1,3 @@
1
1
  module VMCManifests
2
- VERSION = "0.4.13"
2
+ VERSION = "0.4.14"
3
3
  end
@@ -1,9 +1,14 @@
1
1
  require "yaml"
2
2
  require "set"
3
3
 
4
+ require "manifests-vmc-plugin/loader"
5
+
6
+
4
7
  module VMCManifests
5
8
  MANIFEST_FILE = "manifest.yml"
6
9
 
10
+ @@showed_manifest_usage = false
11
+
7
12
  def manifest
8
13
  return @manifest if @manifest
9
14
 
@@ -13,7 +18,7 @@ module VMCManifests
13
18
  end
14
19
 
15
20
  def save_manifest(save_to = manifest_file)
16
- raise "No manifest to save!" unless @manifest
21
+ fail "No manifest to save!" unless @manifest
17
22
 
18
23
  File.open(save_to, "w") do |io|
19
24
  YAML.dump(@manifest, io)
@@ -44,250 +49,67 @@ module VMCManifests
44
49
  @manifest_file = File.expand_path(path)
45
50
  end
46
51
 
47
- # convert any deprecated structuring to the modern format
48
- def simplify_info(info)
49
- if info["framework"].is_a?(Hash)
50
- info["framework"] = info["framework"]["name"]
51
- end
52
- end
53
-
54
52
  # load and resolve a given manifest file
55
53
  def load_manifest(file)
56
- manifest = build_manifest(file)
57
- resolve_manifest(manifest)
58
-
59
- # single-app manifest
60
- simplify_info(manifest)
61
-
62
- if apps = manifest["applications"]
63
- apps.each do |path, info|
64
- simplify_info(info)
65
- end
66
- end
67
-
68
- manifest
69
- end
70
-
71
- # parse a manifest and merge with its inherited manifests
72
- def build_manifest(file)
73
- manifest = YAML.load_file file
74
-
75
- Array(manifest["inherit"]).each do |p|
76
- manifest = merge_parent(manifest, p)
77
- end
78
-
79
- manifest
80
- end
81
-
82
- # merge the manifest at `path' into the `child'
83
- def merge_parent(child, path)
84
- merge_manifest(child, build_manifest(from_manifest(path)))
85
- end
86
-
87
- # deep hash merge
88
- def merge_manifest(child, parent)
89
- merge = proc do |_, old, new|
90
- if new.is_a?(Hash) and old.is_a?(Hash)
91
- old.merge(new, &merge)
92
- else
93
- new
94
- end
95
- end
96
-
97
- parent.merge(child, &merge)
98
- end
99
-
100
- # resolve symbols in a manifest
101
- def resolve_manifest(manifest)
102
- if apps = manifest["applications"]
103
- apps.each_value do |v|
104
- resolve_lexically(v, [manifest])
105
- end
106
- end
107
-
108
- resolve_lexically(manifest, [manifest])
109
-
110
- nil
54
+ Loader.new(file, self).manifest
111
55
  end
112
56
 
113
- # resolve symbols, with hashes introducing new lexical symbols
114
- def resolve_lexically(val, ctx)
115
- case val
116
- when Hash
117
- val.each_value do |v|
118
- resolve_lexically(v, [val] + ctx)
119
- end
120
- when Array
121
- val.each do |v|
122
- resolve_lexically(v, ctx)
123
- end
124
- when String
125
- val.gsub!(/\$\{([^\}]+)\}/) do
126
- resolve_symbol($1, ctx)
127
- end
128
- end
129
-
130
- nil
131
- end
132
-
133
- # resolve a symbol to its value, and then resolve that value
134
- def resolve_symbol(sym, ctx)
57
+ # dynamic symbol resolution
58
+ def resolve_symbol(sym)
135
59
  case sym
136
60
  when "target-url"
137
- target_url(ctx)
61
+ client_target
138
62
 
139
63
  when "target-base"
140
- target_base(ctx)
64
+ client_target.sub(/^[^\.]+\./, "")
141
65
 
142
66
  when "random-word"
143
- "%04x" % [rand(0x0100000)]
67
+ sprintf("%04x", rand(0x0100000))
144
68
 
145
69
  when /^ask (.+)/
146
70
  ask($1)
147
-
148
- else
149
- found = find_symbol(sym, ctx)
150
-
151
- if found
152
- resolve_lexically(found, ctx)
153
- found
154
- else
155
- raise("Unknown symbol in manifest: #{sym}")
156
- end
157
- end
158
- end
159
-
160
- # get the target url from either the manifest or the current client
161
- def target_url(ctx = [])
162
- find_symbol("target", ctx) || client_target
163
- end
164
-
165
- def target_base(ctx = [])
166
- target_url(ctx).sub(/^[^\.]+\./, "")
167
- end
168
-
169
- # search for a symbol introduced in the lexical context
170
- def find_symbol(sym, ctx)
171
- ctx.each do |h|
172
- if val = resolve_in(h, sym)
173
- return val
174
- end
175
- end
176
-
177
- nil
178
- end
179
-
180
- # find a value, searching in explicit properties first
181
- def resolve_in(hash, *where)
182
- find_in_hash(hash, ["properties"] + where) ||
183
- find_in_hash(hash, where)
184
- end
185
-
186
- # helper for following a path of values in a hash
187
- def find_in_hash(hash, where)
188
- what = hash
189
- where.each do |x|
190
- return nil unless what.is_a?(Hash)
191
- what = what[x]
192
- end
193
-
194
- what
195
- end
196
-
197
- MANIFEST_META = ["applications", "properties"]
198
-
199
- def toplevel_attributes
200
- if m = manifest
201
- m.reject do |k, _|
202
- MANIFEST_META.include? k
203
- end
204
71
  end
205
72
  end
206
73
 
207
- def app_by_name(name, input = nil)
208
- return unless manifest
209
-
210
- if apps = manifest["applications"]
211
- manifest["applications"].find do |path, info|
212
- info["name"] == name
213
- end
214
- elsif name == manifest["name"]
215
- [".", toplevel_attributes]
216
- end
74
+ # find an app by its unique tag
75
+ def app_by_tag(tag)
76
+ manifest[:applications][tag]
217
77
  end
218
78
 
219
- def app_by_path(find_path)
220
- return unless manifest
221
-
222
- if apps = manifest["applications"]
223
- full_path = from_manifest(find_path)
224
-
225
- manifest["applications"].find do |path, info|
226
- from_manifest(path) == full_path
227
- end
228
- elsif find_path == "."
229
- [".", toplevel_attributes]
79
+ # find apps by an identifier, which may be either a tag, a name, or a path
80
+ def find_apps(identifier)
81
+ if app = app_by_tag(identifier)
82
+ return [app]
230
83
  end
231
- end
232
-
233
- def app_info(path_or_name, input = nil)
234
- path, info = app_by_name(path_or_name) || app_by_path(path_or_name)
235
- return unless info
236
84
 
237
- data = { :path => path }
238
-
239
- toplevel_attributes.merge(info).each do |k, v|
240
- name = k.to_sym
241
-
242
- if name == :mem
243
- name = :memory
244
- end
85
+ apps = apps_by(:name, identifier)
245
86
 
246
- data[name] = input && input.given(name) || v
87
+ if apps.empty?
88
+ apps = apps_by(:path, from_manifest(identifier))
247
89
  end
248
90
 
249
- data[:path] = from_manifest(data[:path])
250
-
251
- data
91
+ apps
252
92
  end
253
93
 
254
94
  # call a block for each app in a manifest (in dependency order), setting
255
95
  # inputs for each app
256
- def each_app(input = nil, &blk)
257
- if manifest and all_apps = manifest["applications"]
258
- use_inputs = all_apps.size == 1
259
-
260
- ordered_by_deps(all_apps).each do |path|
261
- yield app_info(path, use_inputs && input)
262
- end
263
-
264
- true
265
-
266
- # manually created or legacy single-app manifest
267
- elsif toplevel_attributes
268
- yield app_info(".", input)
269
-
270
- true
96
+ def each_app(&blk)
97
+ return unless manifest
271
98
 
272
- else
273
- false
274
- end
99
+ ordered_by_deps(manifest[:applications]).each(&blk)
275
100
  end
276
101
 
277
- def all_apps(input = nil)
102
+ # return all the apps described by the manifest, in dependency order
103
+ def all_apps
278
104
  apps = []
279
105
 
280
- each_app(input) do |app|
106
+ each_app do |app|
281
107
  apps << app
282
108
  end
283
109
 
284
110
  apps
285
111
  end
286
112
 
287
- def no_apps
288
- fail "No applications or manifest to operate on."
289
- end
290
-
291
113
  # like each_app, but only acts on apps specified as paths instead of names
292
114
  #
293
115
  # returns the names that were not paths
@@ -307,10 +129,12 @@ module VMCManifests
307
129
  in_manifest = []
308
130
 
309
131
  if names_or_paths.empty?
310
- if app = app_info(Dir.pwd, input)
311
- in_manifest << app
132
+ specific = find_apps(Dir.pwd)
133
+
134
+ if !specific.empty?
135
+ in_manifest += apps
312
136
  else
313
- each_app(input, &blk)
137
+ each_app(&blk)
314
138
  return []
315
139
  end
316
140
  end
@@ -320,8 +144,10 @@ module VMCManifests
320
144
  if x.is_a?(String)
321
145
  path = File.expand_path(x)
322
146
 
323
- if app = app_info(File.exists?(path) ? path : x, input)
324
- in_manifest << app
147
+ apps = find_apps(File.exists?(path) ? path : x)
148
+
149
+ if !apps.empty?
150
+ in_manifest += apps
325
151
  elsif app = client.app_by_name(x)
326
152
  external << app
327
153
  else
@@ -339,9 +165,33 @@ module VMCManifests
339
165
  external
340
166
  end
341
167
 
342
-
343
168
  private
344
169
 
170
+ def show_manifest_usage
171
+ return if @@showed_manifest_usage
172
+
173
+ path = Pathname.new(manifest_file).relative_path_from(Pathname.pwd)
174
+ line "Using manifest file #{c(path, :name)}"
175
+ line
176
+
177
+ @@showed_manifest_usage = true
178
+ end
179
+
180
+ def no_apps
181
+ fail "No applications or manifest to operate on."
182
+ end
183
+
184
+ def apps_by(attr, val)
185
+ found = []
186
+ manifest[:applications].each do |tag, info|
187
+ if info[attr] == val
188
+ found << info
189
+ end
190
+ end
191
+
192
+ found
193
+ end
194
+
345
195
  # expand a path relative to the manifest file's directory
346
196
  def from_manifest(path)
347
197
  File.expand_path(path, File.dirname(manifest_file))
@@ -349,35 +199,26 @@ module VMCManifests
349
199
 
350
200
  # sort applications in dependency order
351
201
  # e.g. if A depends on B, B will be listed before A
352
- def ordered_by_deps(apps, abspaths = nil, processed = Set[])
353
- unless abspaths
354
- abspaths = {}
355
- apps.each do |p, i|
356
- abspaths[from_manifest(p)] = i
357
- end
358
- end
359
-
202
+ def ordered_by_deps(apps, processed = Set[])
360
203
  ordered = []
361
- apps.each do |path, info|
362
- epath = from_manifest(path)
204
+ apps.each do |tag, info|
205
+ next if processed.include?(tag)
363
206
 
364
- if deps = info["depends-on"]
207
+ if deps = Array(info[:"depends-on"])
365
208
  dep_apps = {}
366
209
  deps.each do |dep|
367
- edep = from_manifest(dep)
368
-
369
- raise "Circular dependency detected." if processed.include? edep
370
-
371
- dep_apps[dep] = abspaths[edep]
210
+ dep = dep.to_sym
211
+ fail "Circular dependency detected." if processed.include? dep
212
+ dep_apps[dep] = apps[dep]
372
213
  end
373
214
 
374
- processed.add(epath)
215
+ processed.add(tag)
375
216
 
376
- ordered += ordered_by_deps(dep_apps, abspaths, processed)
377
- ordered << path
378
- elsif not processed.include? epath
379
- ordered << path
380
- processed.add(epath)
217
+ ordered += ordered_by_deps(dep_apps, processed)
218
+ ordered << info
219
+ else
220
+ ordered << info
221
+ processed.add(tag)
381
222
  end
382
223
  end
383
224
 
@@ -431,7 +272,7 @@ module VMCManifests
431
272
  with_progress("Saving to #{c("manifest.yml", :name)}") do
432
273
  File.open("manifest.yml", "w") do |io|
433
274
  YAML.dump(
434
- { "applications" => { "." => meta } },
275
+ { "applications" => [meta] },
435
276
  io)
436
277
  end
437
278
  end
@@ -470,19 +311,19 @@ module VMCManifests
470
311
  to_bind << instance
471
312
  else
472
313
  service = services.find { |s|
473
- s.label == (svc["label"] || svc["type"] || svc["vendor"]) &&
474
- (!svc["version"] || s.version == svc["version"]) &&
475
- (s.provider == (svc["provider"] || "core"))
314
+ s.label == (svc[:label] || svc[:type] || svc[:vendor]) &&
315
+ (!svc[:version] || s.version == svc[:version]) &&
316
+ (s.provider == (svc[:provider] || "core"))
476
317
  }
477
318
 
478
319
  fail "Unknown service: #{svc.inspect}." unless service
479
320
 
480
321
  if v2?
481
322
  plan = service.service_plans.find { |p|
482
- p.name == (svc["plan"] || "D100")
323
+ p.name == (svc[:plan] || "D100")
483
324
  }
484
325
 
485
- fail "Unknown service plan: #{svc["plan"]}." unless plan
326
+ fail "Unknown service plan: #{svc[:plan]}." unless plan
486
327
  end
487
328
 
488
329
  invoke :create_service,
@@ -500,32 +341,4 @@ module VMCManifests
500
341
  :instance => i
501
342
  end
502
343
  end
503
-
504
- def megabytes(str)
505
- if str =~ /T$/i
506
- str.to_i * 1024 * 1024
507
- elsif str =~ /G$/i
508
- str.to_i * 1024
509
- elsif str =~ /M$/i
510
- str.to_i
511
- elsif str =~ /K$/i
512
- str.to_i / 1024
513
- else # assume megabytes
514
- str.to_i
515
- end
516
- end
517
-
518
- def human_size(num, precision = 1)
519
- sizes = ["G", "M", "K"]
520
- sizes.each.with_index do |suf, i|
521
- pow = sizes.size - i
522
- unit = 1024 ** pow
523
- if num >= unit
524
- return format("%.#{precision}f%s", num / unit, suf)
525
- end
526
- end
527
-
528
- format("%.#{precision}fB", num)
529
- end
530
-
531
344
  end
@@ -0,0 +1,125 @@
1
+ require "spec_helper"
2
+
3
+ require "manifests-vmc-plugin/loader"
4
+
5
+
6
+ describe VMCManifests::Normalizer do
7
+ let(:manifest) { {} }
8
+ let(:loader) { VMCManifests::Loader.new(nil, nil) }
9
+
10
+ describe '#normalize!' do
11
+ subject do
12
+ loader.normalize!(manifest)
13
+ manifest
14
+ end
15
+
16
+ context 'with a manifest where the applications have no path set' do
17
+ let(:manifest) { { "applications" => { "." => { "name" => "foo" } } } }
18
+
19
+ it "sets the path to their tag, assuming it's a path" do
20
+ expect(subject).to eq(
21
+ :applications => { :"." => { :name => "foo", :path => "." } })
22
+ end
23
+ end
24
+
25
+ context 'with a manifest with toplevel attributes' do
26
+ context 'and properties' do
27
+ let(:manifest) {
28
+ { "name" => "foo", "properties" => { "fizz" => "buzz" } }
29
+ }
30
+
31
+ it 'keeps the properties at the toplevel' do
32
+ expect(subject).to eq(
33
+ :applications => { :"0" => { :name => "foo", :path => "." } },
34
+ :properties => { :fizz => "buzz" })
35
+ end
36
+ end
37
+
38
+ context 'and no applications' do
39
+ context 'and no path' do
40
+ let(:manifest) { { "name" => "foo" } }
41
+
42
+ it 'adds it as an application with path .' do
43
+ expect(subject).to eq(
44
+ :applications => { :"0" => { :name => "foo", :path => "." } })
45
+ end
46
+ end
47
+
48
+ context 'and a path' do
49
+ let(:manifest) { { "name" => "foo", "path" => "./foo" } }
50
+
51
+ it 'adds it as an application with the proper tag and path' do
52
+ expect(subject).to eq(
53
+ :applications => {
54
+ :"0" => { :name => "foo", :path => "./foo" }
55
+ })
56
+ end
57
+ end
58
+ end
59
+
60
+ context 'and applications' do
61
+ let(:manifest) {
62
+ { "runtime" => "ruby19",
63
+ "applications" => {
64
+ "./foo" => { "name" => "foo" },
65
+ "./bar" => { "name" => "bar" },
66
+ "./baz" => { "name" => "baz", "runtime" => "ruby18" }
67
+ }
68
+ }
69
+ }
70
+
71
+ it "merges the toplevel attributes into the applications" do
72
+ expect(subject).to eq(
73
+ :applications => {
74
+ :"./foo" =>
75
+ { :name => "foo", :path => "./foo", :runtime => "ruby19" },
76
+
77
+ :"./bar" =>
78
+ { :name => "bar", :path => "./bar", :runtime => "ruby19" },
79
+
80
+ :"./baz" =>
81
+ { :name => "baz", :path => "./baz", :runtime => "ruby18" }
82
+ })
83
+ end
84
+ end
85
+ end
86
+
87
+ context 'with a manifest where applications is an array' do
88
+ let(:manifest) { { "applications" => [{ "name" => "foo" }] } }
89
+
90
+ it 'converts the array to a hash, with the path as .' do
91
+ expect(subject).to eq(
92
+ :applications => { :"0" => { :name => "foo", :path => "." } })
93
+ end
94
+ end
95
+ end
96
+
97
+ describe '#normalize_app!' do
98
+ subject do
99
+ loader.send(:normalize_app!, manifest)
100
+ manifest
101
+ end
102
+
103
+ context 'with framework as a hash' do
104
+ let(:manifest) {
105
+ { "name" => "foo",
106
+ "framework" => { "name" => "ruby19", "mem" => "64M" }
107
+ }
108
+ }
109
+
110
+ it 'sets the framework to just the name' do
111
+ expect(subject).to eq(
112
+ "name" => "foo",
113
+ "framework" => "ruby19")
114
+ end
115
+ end
116
+
117
+ context 'with mem instead of memory' do
118
+ let(:manifest) { { "name" => "foo", "mem" => "128M" } }
119
+
120
+ it 'renames mem to memory' do
121
+ expect(subject).to eq("name" => "foo", "memory" => "128M")
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,2 @@
1
+ require "cfoundry"
2
+ require "vmc"
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: manifests-vmc-plugin
3
3
  version: !ruby/object:Gem::Version
4
- hash: 21
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 0
8
8
  - 4
9
- - 13
10
- version: 0.4.13
9
+ - 14
10
+ version: 0.4.14
11
11
  platform: ruby
12
12
  authors:
13
13
  - Alex Suraci
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2012-11-20 00:00:00 -08:00
18
+ date: 2012-11-30 00:00:00 -08:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -34,6 +34,51 @@ dependencies:
34
34
  version: 0.4.0
35
35
  type: :runtime
36
36
  version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rake
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :development
50
+ version_requirements: *id002
51
+ - !ruby/object:Gem::Dependency
52
+ name: rspec
53
+ prerelease: false
54
+ requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ~>
58
+ - !ruby/object:Gem::Version
59
+ hash: 3
60
+ segments:
61
+ - 2
62
+ - 0
63
+ version: "2.0"
64
+ type: :development
65
+ version_requirements: *id003
66
+ - !ruby/object:Gem::Dependency
67
+ name: vmc
68
+ prerelease: false
69
+ requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ hash: 15
75
+ segments:
76
+ - 0
77
+ - 4
78
+ - 0
79
+ version: 0.4.0
80
+ type: :development
81
+ version_requirements: *id004
37
82
  description:
38
83
  email:
39
84
  - asuraci@vmware.com
@@ -48,7 +93,13 @@ files:
48
93
  - lib/manifests-vmc-plugin/version.rb
49
94
  - lib/manifests-vmc-plugin/errors.rb
50
95
  - lib/manifests-vmc-plugin/plugin.rb
96
+ - lib/manifests-vmc-plugin/loader.rb
97
+ - lib/manifests-vmc-plugin/loader/normalizer.rb
98
+ - lib/manifests-vmc-plugin/loader/resolver.rb
99
+ - lib/manifests-vmc-plugin/loader/builder.rb
51
100
  - lib/manifests-vmc-plugin.rb
101
+ - spec/spec_helper.rb
102
+ - spec/normalizer_spec.rb
52
103
  has_rdoc: true
53
104
  homepage: http://cloudfoundry.com/
54
105
  licenses: []
@@ -83,5 +134,6 @@ rubygems_version: 1.6.2
83
134
  signing_key:
84
135
  specification_version: 3
85
136
  summary: Cloud Foundry automation via manifest documents.
86
- test_files: []
87
-
137
+ test_files:
138
+ - spec/spec_helper.rb
139
+ - spec/normalizer_spec.rb