manifests-vmc-plugin 0.4.13 → 0.4.14

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.
@@ -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