MrMurano 1.6.3 → 1.7.0

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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -2
  3. data/Gemfile +1 -1
  4. data/MrMurano.gemspec +1 -1
  5. data/README.markdown +4 -0
  6. data/TODO.taskpaper +17 -4
  7. data/lib/MrMurano/Account.rb +5 -1
  8. data/lib/MrMurano/Config.rb +3 -1
  9. data/lib/MrMurano/Product-Resources.rb +239 -0
  10. data/lib/MrMurano/Product.rb +51 -2
  11. data/lib/MrMurano/Solution-Cors.rb +81 -0
  12. data/lib/MrMurano/Solution-Endpoint.rb +8 -4
  13. data/lib/MrMurano/Solution-File.rb +4 -2
  14. data/lib/MrMurano/Solution-ServiceConfig.rb +74 -1
  15. data/lib/MrMurano/Solution-Services.rb +4 -2
  16. data/lib/MrMurano/Solution-Users.rb +6 -3
  17. data/lib/MrMurano/Solution.rb +6 -274
  18. data/lib/MrMurano/SyncUpDown.rb +433 -0
  19. data/lib/MrMurano/commands/completion.rb +152 -0
  20. data/lib/MrMurano/commands/content.rb +15 -14
  21. data/lib/MrMurano/commands/cors.rb +11 -38
  22. data/lib/MrMurano/commands/exportImport.rb +4 -3
  23. data/lib/MrMurano/commands/keystore.rb +15 -16
  24. data/lib/MrMurano/commands/logs.rb +2 -2
  25. data/lib/MrMurano/commands/productCreate.rb +4 -4
  26. data/lib/MrMurano/commands/productDelete.rb +6 -8
  27. data/lib/MrMurano/commands/productSpec.rb +31 -36
  28. data/lib/MrMurano/commands/productWrite.rb +9 -7
  29. data/lib/MrMurano/commands/serialNumberCmds.rb +4 -4
  30. data/lib/MrMurano/commands/solutionCreate.rb +4 -4
  31. data/lib/MrMurano/commands/solutionDelete.rb +5 -5
  32. data/lib/MrMurano/commands/status.rb +9 -42
  33. data/lib/MrMurano/commands/sync.rb +15 -71
  34. data/lib/MrMurano/commands/timeseries.rb +23 -29
  35. data/lib/MrMurano/commands/tsdb.rb +202 -0
  36. data/lib/MrMurano/commands/zshcomplete.erb +112 -0
  37. data/lib/MrMurano/commands.rb +4 -1
  38. data/lib/MrMurano/http.rb +4 -3
  39. data/lib/MrMurano/makePretty.rb +15 -6
  40. data/lib/MrMurano/verbosing.rb +71 -0
  41. data/lib/MrMurano/version.rb +1 -1
  42. data/lib/MrMurano.rb +1 -0
  43. data/spec/ConfigFile_spec.rb +3 -3
  44. data/spec/ProductContent_spec.rb +2 -2
  45. data/spec/ProductResources_spec.rb +152 -0
  46. data/spec/Product_spec.rb +38 -1
  47. data/spec/Solution-Cors_spec.rb +134 -0
  48. data/spec/Solution-ServiceConfig_spec.rb +198 -0
  49. data/spec/SyncRoot_spec.rb +74 -0
  50. data/spec/cmd_config_spec.rb +51 -0
  51. data/spec/fixtures/.mrmuranorc +9 -0
  52. data/spec/{testfiles → fixtures}/configfile +0 -0
  53. data/spec/fixtures/mrmuranorc_deleted_bob +8 -0
  54. data/spec/fixtures/product_spec_files/example.exoline.spec.yaml +116 -0
  55. data/spec/fixtures/product_spec_files/example.murano.spec.yaml +14 -0
  56. data/spec/fixtures/product_spec_files/gwe.exoline.spec.yaml +21 -0
  57. data/spec/fixtures/product_spec_files/gwe.murano.spec.yaml +16 -0
  58. data/spec/{lightbulb.yaml → fixtures/product_spec_files/lightbulb.yaml} +0 -0
  59. data/spec/spec_helper.rb +4 -4
  60. metadata +47 -19
@@ -0,0 +1,433 @@
1
+ require 'pathname'
2
+ require 'tempfile'
3
+ require 'shellwords'
4
+ require 'MrMurano/Config'
5
+ require 'MrMurano/hash'
6
+
7
+ module MrMurano
8
+ class SyncRoot
9
+ Syncable = Struct.new(:name, :class, :type, :desc, :bydefault) do
10
+ end
11
+
12
+ def self.add(name, klass, type, desc, bydefault=false)
13
+ @@syncset = [] unless defined?(@@syncset)
14
+ @@syncset << Syncable.new(name.to_s, klass, type, desc, bydefault)
15
+ end
16
+
17
+ def self.reset()
18
+ @@syncset = []
19
+ end
20
+
21
+ def self.each(&block)
22
+ @@syncset.each{|a| yield a.name, a.type, a.class }
23
+ end
24
+
25
+ def self.each_option(&block)
26
+ @@syncset.each{|a| yield "-#{a.type.downcase}", "--[no-]#{a.name}", a.desc}
27
+ end
28
+
29
+ def self.each_filtered(opt, &block)
30
+ self.checkSAME(opt)
31
+ @@syncset.each do |a|
32
+ if opt[a.name.to_sym] or opt[a.type.to_sym] then
33
+ yield a.name, a.type, a.class
34
+ end
35
+ end
36
+ end
37
+
38
+ ## Adjust options based on all or none
39
+ # If none are selected, select the bydefault ones.
40
+ def self.checkSAME(opt)
41
+ if opt[:all] then
42
+ @@syncset.each {|a| opt[a.name.to_sym] = true }
43
+ else
44
+ any = @@syncset.select {|a| opt[a.name.to_sym] or opt[a.type.to_sym]}
45
+ if any.empty? then
46
+ @@syncset.select{|a| a.bydefault }.each{|a| opt[a.name.to_sym] = true}
47
+ end
48
+ end
49
+
50
+ nil
51
+ end
52
+ end
53
+
54
+ module SyncUpDown
55
+ #######################################################################
56
+ # Methods that must be overridden
57
+
58
+ ##
59
+ # Get a list of remote items.
60
+ #
61
+ # Children objects Must override this
62
+ #
63
+ # @return Array: of Hashes of item details
64
+ def list()
65
+ []
66
+ end
67
+
68
+ ## Remove remote item
69
+ #
70
+ # Children objects Must override this
71
+ #
72
+ # @param itemkey String: The identifying key for this item
73
+ def remove(itemkey)
74
+ raise "Forgotten implementation"
75
+ end
76
+
77
+ ## Upload local item to remote
78
+ #
79
+ # Children objects Must override this
80
+ #
81
+ # @param src Pathname: Full path of where to upload from
82
+ # @param item Hash: The item details to upload
83
+ # @param modify Bool: True if item exists already and this is changing it
84
+ def upload(src, item, modify)
85
+ raise "Forgotten implementation"
86
+ end
87
+
88
+ ##
89
+ # True if itemA and itemB are different
90
+ #
91
+ # Children objects must override this
92
+ #
93
+ def docmp(itemA, itemB)
94
+ true
95
+ end
96
+
97
+ #
98
+ #######################################################################
99
+
100
+ #######################################################################
101
+ # Methods that could be overriden
102
+
103
+ ##
104
+ # Compute a remote item hash from the local path
105
+ #
106
+ # Children objects should override this.
107
+ #
108
+ # @param root Pathname: Root path for this resource type from config files
109
+ # @param path Pathname: Path to local item
110
+ # @return Hash: hash of the details for the remote item for this path
111
+ def toRemoteItem(root, path)
112
+ path = Pathname.new(path) unless path.kind_of? Pathname
113
+ root = Pathname.new(root) unless root.kind_of? Pathname
114
+ {:name => path.relative_path_from(root).to_s}
115
+ end
116
+
117
+ ##
118
+ # Compute the local name from remote item details
119
+ #
120
+ # Children objects should override this or #tolocalpath
121
+ #
122
+ # @param item Hash: listing details for the item.
123
+ # @param itemkey Symbol: Key for look up.
124
+ def tolocalname(item, itemkey)
125
+ item[itemkey].to_s
126
+ end
127
+
128
+ ##
129
+ # Compute the local path from the listing details
130
+ #
131
+ # If there is already a matching local item, some of its details are also in
132
+ # the item hash.
133
+ #
134
+ # Children objects should override this or #tolocalname
135
+ #
136
+ # @param into Pathname: Root path for this resource type from config files
137
+ # @param item Hash: listing details for the item.
138
+ # @return Pathname: path to save (or merge) remote item into
139
+ def tolocalpath(into, item)
140
+ return item[:local_path] if item.has_key? :local_path
141
+ itemkey = @itemkey.to_sym
142
+ name = tolocalname(item, itemkey)
143
+ raise "Bad key(#{itemkey}) for #{item}" if name.nil?
144
+ name = Pathname.new(name) unless name.kind_of? Pathname
145
+ name = name.relative_path_from(Pathname.new('/')) if name.absolute?
146
+ into + name
147
+ end
148
+
149
+ ## Get the key used to quickly compare two items
150
+ #
151
+ # Children objects should override this if synckey is not @itemkey
152
+ #
153
+ # @param item Hash: The item to get a key from
154
+ # @returns Object: The object to use a comparison key
155
+ def synckey(item)
156
+ key = @itemkey.to_sym
157
+ item[key]
158
+ end
159
+
160
+ ## Download an item into local
161
+ #
162
+ # Children objects should override this or implement #fetch()
163
+ #
164
+ # @param local Pathname: Full path of where to download to
165
+ # @param item Hash: The item to download
166
+ def download(local, item)
167
+ if item[:bundled] then
168
+ say_warning "Not downloading into bundled item #{synckey(item)}"
169
+ # FIXME don't use say_warning
170
+ return
171
+ end
172
+ local.dirname.mkpath
173
+ id = item[@itemkey.to_sym]
174
+ local.open('wb') do |io|
175
+ fetch(id) do |chunk|
176
+ io.write chunk
177
+ end
178
+ end
179
+ end
180
+
181
+ ## Remove local reference of item
182
+ #
183
+ # Children objects should override this if move than just unlinking the local
184
+ # item.
185
+ #
186
+ # @param dest Pathname: Full path of item to be removed
187
+ # @param item Hash: Full details of item to be removed
188
+ def removelocal(dest, item)
189
+ dest.unlink
190
+ end
191
+
192
+ #
193
+ #######################################################################
194
+
195
+
196
+ ##
197
+ # So, for bundles this needs to look at all the places and build up the mered
198
+ # stack of local items.
199
+ #
200
+ # Which means it needs the from to be split into the base and the sub so we can
201
+ # inject bundle directories.
202
+
203
+ ##
204
+ # Get a list of local items.
205
+ #
206
+ # Children should never need to override this. Instead they should override
207
+ # #localitems
208
+ #
209
+ # This collects items in the project and all bundles.
210
+ # @return Array: of Hashes of items
211
+ def locallist()
212
+ # so. if @locationbase/bundles exists
213
+ # gather and merge: @locationbase/bundles/*/@location
214
+ # then merge @locationbase/@location
215
+ #
216
+
217
+ bundleDir = $cfg['location.bundles'] or 'bundles'
218
+ bundleDir = 'bundles' if bundleDir.nil?
219
+ items = {}
220
+ if (@locationbase + bundleDir).directory? then
221
+ (@locationbase + bundleDir).children.sort.each do |bndl|
222
+ if (bndl + @location).exist? then
223
+ verbose("Loading from bundle #{bndl.basename}")
224
+ bitems = localitems(bndl + @location)
225
+ bitems.map!{|b| b[:bundled] = true; b} # mark items from bundles.
226
+
227
+
228
+ # use synckey for quicker merging.
229
+ bitems.each { |b| items[synckey(b)] = b }
230
+ end
231
+ end
232
+ end
233
+ if (@locationbase + @location).exist? then
234
+ bitems = localitems(@locationbase + @location)
235
+ # use synckey for quicker merging.
236
+ bitems.each { |b| items[synckey(b)] = b }
237
+ end
238
+
239
+ items.values
240
+ end
241
+
242
+ ##
243
+ # Get a list of local items rooted at #from
244
+ #
245
+ # Children rarely need to override this. Only when the locallist is not a set
246
+ # of files in a directory will they need to override it.
247
+ #
248
+ # @param from Pathname: Directory of items to scan
249
+ # @return Array: of Hashes of item details
250
+ def localitems(from)
251
+ from.children.map do |path|
252
+ if path.directory? then
253
+ # TODO: look for definition. ( ?.rockspec? ?mr.modules? ?mr.manifest? )
254
+ # Lacking definition, find all *.lua but not *_test.lua
255
+ # This specifically and intentionally only goes one level deep.
256
+ path.children
257
+ else
258
+ path
259
+ end
260
+ end.flatten.compact.reject do |path|
261
+ path.fnmatch('*_test.lua') or path.basename.fnmatch('.*')
262
+ end.select do |path|
263
+ path.extname == '.lua'
264
+ end.map do |path|
265
+ # sometimes this is a name, sometimes it is an item.
266
+ # do I want to keep that? NO.
267
+ name = toRemoteItem(from, path)
268
+ unless name.nil? then
269
+ name[:local_path] = path
270
+ name
271
+ end
272
+ end.flatten.compact
273
+ end
274
+
275
+ #######################################################################
276
+ # Methods that provide the core status/syncup/syncdown
277
+
278
+ def elevate_hash(hsh)
279
+ if hsh.kind_of?(Hash) then
280
+ hsh = Hash.transform_keys_to_symbols(hsh)
281
+ hsh.define_singleton_method(:method_missing) do |mid,*args|
282
+ if mid.to_s.match(/^(.+)=$/) then
283
+ self[$1.to_sym] = args.first
284
+ else
285
+ self[mid]
286
+ end
287
+ end
288
+ end
289
+ hsh
290
+ end
291
+ private :elevate_hash
292
+
293
+ def syncup(options={})
294
+ options = elevate_hash(options)
295
+ itemkey = @itemkey.to_sym
296
+ options.asdown=false
297
+ dt = status(options)
298
+ toadd = dt[:toadd]
299
+ todel = dt[:todel]
300
+ tomod = dt[:tomod]
301
+
302
+ if options.delete then
303
+ todel.each do |item|
304
+ verbose "Removing item #{item[:synckey]}"
305
+ unless $cfg['tool.dry'] then
306
+ remove(item[itemkey])
307
+ end
308
+ end
309
+ end
310
+ if options.create then
311
+ toadd.each do |item|
312
+ verbose "Adding item #{item[:synckey]}"
313
+ unless $cfg['tool.dry'] then
314
+ upload(item[:local_path], item.reject{|k,v| k==:local_path}, false)
315
+ end
316
+ end
317
+ end
318
+ if options.update then
319
+ tomod.each do |item|
320
+ verbose "Updating item #{item[:synckey]}"
321
+ unless $cfg['tool.dry'] then
322
+ upload(item[:local_path], item.reject{|k,v| k==:local_path}, true)
323
+ end
324
+ end
325
+ end
326
+ end
327
+
328
+ def syncdown(options={})
329
+ options = elevate_hash(options)
330
+ options.asdown = true
331
+ dt = status(options)
332
+ into = @locationbase + @location ###
333
+ toadd = dt[:toadd]
334
+ todel = dt[:todel]
335
+ tomod = dt[:tomod]
336
+
337
+ if options.delete then
338
+ todel.each do |item|
339
+ verbose "Removing item #{item[:synckey]}"
340
+ unless $cfg['tool.dry'] then
341
+ dest = tolocalpath(into, item)
342
+ removelocal(dest, item)
343
+ end
344
+ end
345
+ end
346
+ if options.create then
347
+ toadd.each do |item|
348
+ verbose "Adding item #{item[:synckey]}"
349
+ unless $cfg['tool.dry'] then
350
+ dest = tolocalpath(into, item)
351
+ download(dest, item)
352
+ end
353
+ end
354
+ end
355
+ if options.update then
356
+ tomod.each do |item|
357
+ verbose "Updating item #{item[:synckey]}"
358
+ unless $cfg['tool.dry'] then
359
+ dest = tolocalpath(into, item)
360
+ download(dest, item)
361
+ end
362
+ end
363
+ end
364
+ end
365
+
366
+ ## Call external diff tool on item
367
+ # WARNING: This will download the remote item to do the diff.
368
+ # @param item Hash: The item to get a diff of
369
+ # @return String: The diff output
370
+ def dodiff(item)
371
+ tfp = Tempfile.new([tolocalname(item, @itemkey), '.lua'])
372
+ df = ""
373
+ begin
374
+ download(Pathname.new(tfp.path), item)
375
+
376
+ cmd = $cfg['diff.cmd'].shellsplit
377
+ cmd << tfp.path
378
+ cmd << item[:local_path].to_s
379
+
380
+ IO.popen(cmd) {|io| df = io.read }
381
+ ensure
382
+ tfp.close
383
+ tfp.unlink
384
+ end
385
+ df
386
+ end
387
+
388
+ ## Get status of things here verses there
389
+ def status(options={})
390
+ options = elevate_hash(options)
391
+ there = list()
392
+ here = locallist()
393
+ itemkey = @itemkey.to_sym
394
+
395
+ therebox = {}
396
+ there.each do |item|
397
+ item = Hash.transform_keys_to_symbols(item)
398
+ item[:synckey] = synckey(item)
399
+ therebox[ item[:synckey] ] = item
400
+ end
401
+ herebox = {}
402
+ here.each do |item|
403
+ item = Hash.transform_keys_to_symbols(item)
404
+ item[:synckey] = synckey(item)
405
+ herebox[ item[:synckey] ] = item
406
+ end
407
+ toadd = []
408
+ todel = []
409
+ tomod = []
410
+ unchg = []
411
+ if options.asdown then
412
+ todel = (herebox.keys - therebox.keys).map{|key| herebox[key] }
413
+ toadd = (therebox.keys - herebox.keys).map{|key| therebox[key] }
414
+ else
415
+ toadd = (herebox.keys - therebox.keys).map{|key| herebox[key] }
416
+ todel = (therebox.keys - herebox.keys).map{|key| therebox[key] }
417
+ end
418
+ (herebox.keys & therebox.keys).each do |key|
419
+ # Want here to override there except for itemkey.
420
+ mrg = herebox[key].reject{|k,v| k==itemkey}
421
+ mrg = therebox[key].merge(mrg)
422
+ if docmp(herebox[key], therebox[key]) then
423
+ mrg[:diff] = dodiff(mrg) if options.diff
424
+ tomod << mrg
425
+ else
426
+ unchg << mrg
427
+ end
428
+ end
429
+ { :toadd=>toadd, :todel=>todel, :tomod=>tomod, :unchg=>unchg }
430
+ end
431
+ end
432
+ end
433
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,152 @@
1
+ require 'pp'
2
+ require 'erb'
3
+
4
+ class CompletionContext < ::Commander::HelpFormatter::Context
5
+ end
6
+
7
+ class ::Commander::Runner
8
+
9
+ # Not so sure this should go in Runner, but where else?
10
+
11
+ ##
12
+ # Change the '--[no-]foo' switch into '--no-foo' and '--foo'
13
+ def flatswitches(option)
14
+ # if there is a --[no-]foo format, break that into two switches.
15
+ option[:switches].map{ |switch|
16
+ switch = switch.sub(/\s.*$/,'') # drop argument spec if exists.
17
+ if switch =~ /\[no-\]/ then
18
+ [switch.sub(/\[no-\]/, ''), switch.gsub(/[\[\]]/,'')]
19
+ else
20
+ switch
21
+ end
22
+ }.flatten
23
+ end
24
+
25
+ ##
26
+ # If the switches take an argument, retun =
27
+ def takesArg(option, yes='=', no='')
28
+ if option[:switches].select { |switch| switch =~ /\s\S+$/ }.empty? then
29
+ no
30
+ else
31
+ yes
32
+ end
33
+ end
34
+
35
+ ##
36
+ # truncate the description of an option
37
+ def optionDesc(option)
38
+ option[:description].sub(/\n.*$/,'')
39
+ end
40
+
41
+ ##
42
+ # Get a tree of all commands and sub commands
43
+ def cmdTree
44
+ tree={}
45
+ @commands.sort.each do |name,cmd|
46
+ levels = name.split
47
+ pos = tree
48
+ levels.each do |step|
49
+ pos[step] = {} unless pos.has_key? step
50
+ pos = pos[step]
51
+ end
52
+ pos["\0cmd"] = cmd
53
+ end
54
+ tree
55
+ end
56
+
57
+ ##
58
+ # Get maximum depth of sub-commands.
59
+ def cmdMaxDepth
60
+ depth=0
61
+ @commands.sort.each do |name,cmd|
62
+ levels = name.split
63
+ depth = levels.count if levels.count > depth
64
+ end
65
+ depth
66
+ end
67
+
68
+ ##
69
+ # Alternate tree of sub-commands.
70
+ def cmdTreeB
71
+ tree={}
72
+ @commands.sort.each do |name,cmd|
73
+ levels = name.split
74
+ tree[levels.join(' ')] = {:cmd=>cmd}
75
+
76
+ # load parent.
77
+ left = levels[0..-2]
78
+ right = levels[-1]
79
+ key = left.join(' ')
80
+ tree[key] = {} unless tree.has_key? key
81
+ if tree[key].has_key?(:subs) then
82
+ tree[key][:subs] << right
83
+ else
84
+ tree[key][:subs] = [right]
85
+ end
86
+ end
87
+ tree
88
+ end
89
+
90
+ end
91
+
92
+ command :completion do |c|
93
+ c.syntax = %{mr completion}
94
+ c.summary = %{Generate a completion file}
95
+ c.description = %{For starts, this is zsh only. Because that is what I use.
96
+
97
+ eval "$(mr completion)"
98
+ or
99
+ mr completion > _mr
100
+ source _mr
101
+ }
102
+ c.option '--subs', 'List sub commands'
103
+ #c.option '--opts CMD', 'List options for subcommand'
104
+ #c.option '--gopts', 'List global options'
105
+
106
+ # Changing direction.
107
+ # Will poop out the file to be included as the completion script.
108
+
109
+ c.action do |args, options|
110
+
111
+ runner = ::Commander::Runner.instance
112
+
113
+ if options.gopts then
114
+ opts = runner.instance_variable_get(:@options)
115
+ pp opts.first
116
+ pp runner.takesArg(opts.first)
117
+ # opts.each do |o|
118
+ # puts runner.optionLine o, 'GlobalOption'
119
+ # end
120
+
121
+ elsif options.subs then
122
+ runner.instance_variable_get(:@commands).sort.each do |name,cmd|
123
+ #desc = cmd.instance_variable_get(:@summary) #.lines[0]
124
+ #say "#{name}:'#{desc}'"
125
+ say "#{name}"
126
+ end
127
+
128
+ elsif options.opts then
129
+ cmds = runner.instance_variable_get(:@commands)
130
+ cmd = cmds[options.opts]
131
+ pp cmd.syntax
132
+ # looking at OptionParser to help figure out what kind of params a switch
133
+ # gets. And hopefully derive a completer for it
134
+ # !!!!! OptionParser::Completion what is this?
135
+ opts = OptionParser.new
136
+ cmds[options.opts].options.each do |o|
137
+ pp opts.make_switch(o[:args])
138
+ end
139
+
140
+ else
141
+
142
+ tmpl=ERB.new(File.read(File.join(File.dirname(__FILE__), "zshcomplete.erb")), nil, '-<>')
143
+
144
+ pc = CompletionContext.new(runner)
145
+ puts tmpl.result(pc.get_binding)
146
+ end
147
+
148
+
149
+ end
150
+ end
151
+
152
+ # vim: set ai et sw=2 ts=2 :
@@ -1,3 +1,4 @@
1
+ require 'MrMurano/Product'
1
2
 
2
3
  command 'content list' do |c|
3
4
  c.syntax = %{mr content list}
@@ -9,7 +10,7 @@ command 'content list' do |c|
9
10
  }
10
11
  c.action do |args, options|
11
12
  prd = MrMurano::ProductContent.new
12
- prd.list.each{|item| say item}
13
+ prd.outf prd.list
13
14
  end
14
15
  end
15
16
  alias_command :content, 'content list'
@@ -23,11 +24,11 @@ command 'content info' do |c|
23
24
  HTTP Device API. (http://docs.exosite.com/http/#list-available-content)
24
25
  }
25
26
  c.action do |args, options|
27
+ prd = MrMurano::ProductContent.new
26
28
  if args[0].nil? then
27
- say_error "Missing <content id>"
29
+ prd.error "Missing <content id>"
28
30
  else
29
- prd = MrMurano::ProductContent.new
30
- prd.info(args[0]).each{|line| say "#{args[0]} #{line.join(' ')}"}
31
+ prd.tabularize prd.info(args[0])
31
32
  end
32
33
  end
33
34
  end
@@ -41,11 +42,11 @@ command 'content delete' do |c|
41
42
  HTTP Device API. (http://docs.exosite.com/http/#list-available-content)
42
43
  }
43
44
  c.action do |args, options|
45
+ prd = MrMurano::ProductContent.new
44
46
  if args[0].nil? then
45
- say_error "Missing <content id>"
47
+ prd.error "Missing <content id>"
46
48
  else
47
- prd = MrMurano::ProductContent.new
48
- pp prd.remove(args[0])
49
+ prd.outf prd.remove(args[0])
49
50
  end
50
51
  end
51
52
  end
@@ -62,20 +63,20 @@ command 'content upload' do |c|
62
63
 
63
64
  c.action do |args, options|
64
65
  options.defaults :meta=>' '
66
+ prd = MrMurano::ProductContent.new
65
67
 
66
68
  if args[0].nil? then
67
- say_error "Missing <content id>"
69
+ prd.error "Missing <content id>"
68
70
  elsif args[1].nil? then
69
- say_error "Missing <file>"
71
+ prd.error "Missing <file>"
70
72
  else
71
- prd = MrMurano::ProductContent.new
72
73
 
73
74
  ret = prd.info(args[0])
74
75
  if ret.nil? then
75
- pp prd.create(args[0], options.meta)
76
+ prd.outf prd.create(args[0], options.meta)
76
77
  end
77
78
 
78
- pp prd.upload(args[0], args[1])
79
+ prd.outf prd.upload(args[0], args[1])
79
80
  end
80
81
  end
81
82
  end
@@ -90,10 +91,10 @@ command 'content download' do |c|
90
91
  }
91
92
  c.option '-o','--output FILE',%{save to this file}
92
93
  c.action do |args, options|
94
+ prd = MrMurano::ProductContent.new
93
95
  if args[0].nil? then
94
- say_error "Missing <content id>"
96
+ prd.error "Missing <content id>"
95
97
  else
96
- prd = MrMurano::ProductContent.new
97
98
 
98
99
  if options.output.nil? then
99
100
  prd.download(args[0]) # to stdout