MrMurano 1.6.3 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6a025c5dcac4ea0902844834d8a91fe8ddbef68d
4
- data.tar.gz: d409283477356d621bb94b14e1a98a8a7c2ed7f8
3
+ metadata.gz: 08052f794adafafd1df94b8ddb72a1b604ead821
4
+ data.tar.gz: 4554d9ecf88eacc3af079263f10046b882fc4aa4
5
5
  SHA512:
6
- metadata.gz: 6f00e7636e61805ebe1f92d36009ce0a4f0f8ccb227f896b4ba2ff11dbecdb5a15ac4106b016ab889fb85b078f4c830247faea69c7cab397a19c1288f189f751
7
- data.tar.gz: a8bbe3938bce7d0ae4e876d916916823f793cbeac9dddcf3ba72359bb0d16994d2c3be5051046cb73c717ec23f1c341070266b320b31da8a9d5349f7d8a9f47d
6
+ metadata.gz: dbc7d9cabe0efaf8a613b39dc636c353aec46ec5d3bf6de7761be4f810b96ae547d4490b6e077c4c586999a00fff88da44111c8a04f51cd618ad746bcc90a8e7
7
+ data.tar.gz: fe92deb1e28bb05c11e7a5b274b89afe90b9c8ef1935c6f105cc842e36f657ec3776eb2d3101d4756997f1ae5d8523d575c65dc568675fc68377e08efd07f05a
data/.gitignore CHANGED
@@ -4,8 +4,7 @@
4
4
  Icon
5
5
  *.sw[a-z]
6
6
  cookies
7
- .jiraProject
8
- .rpjProject
7
+ .jiramulerc
9
8
  tags
10
9
 
11
10
  xcuserdata
data/Gemfile CHANGED
@@ -3,12 +3,12 @@ source 'http://rubygems.org'
3
3
  #gemspec
4
4
 
5
5
  gem 'commander', '~> 4.4.0'
6
+ gem 'highline', '~> 1.7.8'
6
7
  gem 'terminal-table', '~> 1.4.5'
7
8
  gem 'mime-types', '~> 1.25.1'
8
9
  gem 'mime-types-data', '~> 3.2016'
9
10
  gem 'inifile', '~> 3.0'
10
11
  gem 'http-form_data', '~> 1.0.1'
11
- gem 'rainbow', '~> 2.1.0'
12
12
  gem 'dotenv', '~> 2.1.1'
13
13
 
14
14
  group :test do
data/MrMurano.gemspec CHANGED
@@ -25,12 +25,12 @@ Gem::Specification.new do |s|
25
25
  s.require_paths = ['lib']
26
26
 
27
27
  s.add_runtime_dependency('commander', '~> 4.4.0')
28
+ s.add_runtime_dependency('highline', '~> 1.7.8')
28
29
  s.add_runtime_dependency('terminal-table', '~> 1.4.5')
29
30
  s.add_runtime_dependency('mime-types', '~> 1.25.1')
30
31
  s.add_runtime_dependency('mime-types-data', '~> 3.2016')
31
32
  s.add_runtime_dependency('inifile', '~> 3.0')
32
33
  s.add_runtime_dependency('http-form_data', '~> 1.0.1')
33
- s.add_runtime_dependency('rainbow', '~> 2.1.0')
34
34
  s.add_runtime_dependency('dotenv', '~> 2.1.1')
35
35
 
36
36
  s.add_development_dependency('bundler', '~> 1.7.6')
data/README.markdown CHANGED
@@ -134,6 +134,10 @@ following commands:
134
134
 
135
135
  Call them with `--help` for details.
136
136
 
137
+ ### ZSH tab completion
138
+
139
+ Basic completion support for zsh.
140
+
137
141
  ### Sub-directories
138
142
 
139
143
  For the endpoints, modules, and eventhandlers directories. The can contain both
data/TODO.taskpaper CHANGED
@@ -1,8 +1,12 @@
1
1
  Readme:
2
2
  - Add more walk-thrus of common actions. (create new solution, …)
3
- - Look into using VCR for testing.
3
+ - Look into using VCR for testing. @pri(low)
4
4
 
5
5
  Commands:
6
+ - Errors and Warnings should get sent to STDERR @done(2016-11-03)
7
+ - Need a more consistent output format. 'pp' is still used in many places. @done(2016-11-03)
8
+ Maybe have a tool setting for output format? json, yaml, pp, csv, table ?
9
+ - Do we need rainbow since highline does ANSI color too? @done(2016-11-02)
6
10
  - Status will show {modules,eventhandlers} have changes when they don’t. @done(2016-09-23)
7
11
  - First time run needs to be smoothed out. @done(2016-08-09)
8
12
  - Default for most commands should be -same @done(2016-08-02)
@@ -18,7 +22,7 @@ Endpoints:
18
22
 
19
23
  Files:
20
24
  - Add ignore patterns to config
21
- - Switch to mime-types v3
25
+ - Switch to mime-types v3 @pri(low)
22
26
  - Figure out how to make the hexed-sha checksum faster. @done(2016-09-23)
23
27
  - Fix upload. @done(2016-08-01)
24
28
  - Files won't update, they always delete then add. @done(2016-07-28)
@@ -31,14 +35,18 @@ Users and Roles:
31
35
  - Have hash keys in the yaml be strings not symbols. (don't start with colon) @done(2016-07-27)
32
36
 
33
37
  CORS:
34
- - Get working with sync up/down.
38
+ - Get working with sync up/down. @done(2016-10-28)
35
39
  - GET&PUT /cors data @done(2016-09-08)
36
40
 
41
+ TSDB:
42
+ - Add support for new TSDB service. @pri(high)
43
+
37
44
  Timeseries:
38
45
  - Add CSV output option. @done(2016-09-09)
39
46
 
40
47
  Product:
41
- - Auto convert exoline spec files into murano spec files on upload?
48
+ - Auto convert exoline spec files into murano spec files on upload? @done(2016-10-27)
49
+ Not doing this. Convert is there if you need it.
42
50
  - write alias command @done(2016-09-26)
43
51
  - Need to add way to set the product ID on a device eventhandler. @done(2016-08-01)
44
52
 
@@ -57,7 +65,12 @@ SolutionBase:
57
65
  - Add the --curl verbose option. @done(2016-08-12)
58
66
  - Rebuild how local names and paths are computed from remote items. @done(2016-07-27)
59
67
 
68
+ Windows:
69
+ - Need to test with http://rubyinstaller.org on Windows. @pri(high)
70
+ - Look into http://ocra.rubyforge.org for building an exec. @pri(high)
71
+
60
72
  Bundles:
73
+ - Revisit this idea. Its complexity may not be worth its value.
61
74
  - Test syncdown behavor.
62
75
  - Work on design @done(2016-08-09)
63
76
  Thinking of something like VIM bundles. A directory of directories. Each with a
@@ -6,6 +6,7 @@ require 'pathname'
6
6
  require 'yaml'
7
7
  require 'MrMurano/Config'
8
8
  require 'MrMurano/http'
9
+ require 'MrMurano/verbosing'
9
10
 
10
11
  module MrMurano
11
12
  class Passwords
@@ -53,6 +54,7 @@ module MrMurano
53
54
 
54
55
  class Account
55
56
  include Http
57
+ include Verbose
56
58
 
57
59
  def endPoint(path)
58
60
  URI('https://' + $cfg['net.host'] + '/api:1/' + path.to_s)
@@ -62,7 +64,8 @@ module MrMurano
62
64
  host = $cfg['net.host']
63
65
  user = $cfg['user.name']
64
66
  if user.nil? then
65
- user = ask("Account name: ")
67
+ say_error("No Murano user account found; please login")
68
+ user = ask("User name: ")
66
69
  $cfg.set('user.name', user, :user)
67
70
  end
68
71
  pff = $cfg.file_at('passwords', :user)
@@ -70,6 +73,7 @@ module MrMurano
70
73
  pf.load
71
74
  pws = pf.get(host, user)
72
75
  if pws.nil? then
76
+ say_error("Couldn't find password for #{user}")
73
77
  pws = ask("Password: ") { |q| q.echo = "*" }
74
78
  pf.set(host, user, pws)
75
79
  pf.save
@@ -71,6 +71,7 @@ module MrMurano
71
71
  set('tool.verbose', false, :defaults)
72
72
  set('tool.debug', false, :defaults)
73
73
  set('tool.dry', false, :defaults)
74
+ set('tool.outformat', 'best', :defaults)
74
75
 
75
76
  set('net.host', 'bizapi.hosted.exosite.io', :defaults)
76
77
 
@@ -81,6 +82,7 @@ module MrMurano
81
82
  set('location.eventhandlers', 'eventhandlers', :defaults)
82
83
  set('location.roles', 'roles.yaml', :defaults)
83
84
  set('location.users', 'users.yaml', :defaults)
85
+ set('location.cors', 'cors.yaml', :defaults)
84
86
 
85
87
  set('files.default_page', 'index.html', :defaults)
86
88
 
@@ -244,7 +246,7 @@ module MrMurano
244
246
  # IF none of -same, then -same; else just the ones listed.
245
247
  def self.checkSAME(opt)
246
248
  unless opt.files or opt.endpoints or opt.modules or
247
- opt.eventhandlers or opt.roles or opt.users then
249
+ opt.eventhandlers or opt.roles or opt.users or opt.spec then
248
250
  opt.files = true
249
251
  opt.endpoints = true
250
252
  opt.modules = true
@@ -0,0 +1,239 @@
1
+ require 'MrMurano/Product'
2
+ require 'MrMurano/SyncUpDown'
3
+
4
+ module MrMurano
5
+
6
+ ## Manage the resources on a Product
7
+ #
8
+ # There isn't an okami-shim for most of this, it maps right over to 1P-RPC.
9
+ # Or better stated, that's all okami-shim is.
10
+ class ProductResources < ProductBase
11
+ include SyncUpDown
12
+
13
+ def initialize
14
+ super
15
+ @uriparts << :proxy
16
+ @uriparts << 'onep:v1'
17
+ @uriparts << :rpc
18
+ @uriparts << :process
19
+ @model_rid = nil
20
+
21
+ @itemkey = :rid # this is the key that is the identifier used by murano
22
+ @location = location
23
+ end
24
+
25
+ ## Get the location of the product spec file
26
+ def location
27
+ # If location.specs is defined, then all spec files are assume to be relative
28
+ # to that and location.base, otherwise they're relative to only location.base
29
+ #
30
+ # If there is a p-<product.id>.spec key, then that is the file name.
31
+ # Otherwise use product.spec
32
+
33
+ name = $cfg['product.spec']
34
+ prid = $cfg['product.id']
35
+ name = $cfg["p-#{prid}.spec"] unless prid.nil? or $cfg["p-#{prid}.spec"].nil?
36
+
37
+ unless $cfg['location.specs'].nil? then
38
+ name = File.join($cfg['location.specs'], name)
39
+ end
40
+ name
41
+ end
42
+
43
+ ## The model RID for this product.
44
+ def model_rid
45
+ return @model_rid unless @model_rid.nil?
46
+ prd = Product.new
47
+ data = prd.info
48
+ if data.kind_of?(Hash) and data.has_key?(:modelrid) then
49
+ @model_rid = data[:modelrid]
50
+ else
51
+ raise "Bad info; #{data}"
52
+ end
53
+ @model_rid
54
+ end
55
+
56
+ ## Do a 1P RPC call
57
+ #
58
+ # While this will take an array of calls, don't. Only pass one.
59
+ def do_rpc(calls)
60
+ calls = [calls] unless calls.kind_of?(Array)
61
+ r = post('', {
62
+ :auth=>{:client_id=>model_rid},
63
+ :calls=>calls
64
+ })
65
+ return r if not r.kind_of?(Array) or r.count < 1
66
+ r = r[0]
67
+ return r if not r.kind_of?(Hash) or r[:status] != 'ok'
68
+ r[:result]
69
+ end
70
+ private :do_rpc
71
+
72
+ ## Get 1P info about the prodcut
73
+ def info
74
+ do_rpc({:id=>1,
75
+ :procedure=>:info,
76
+ :arguments=>[model_rid, {}]
77
+ })
78
+ end
79
+
80
+ ## Return a list of the product resources as items
81
+ def list()
82
+ data = info()
83
+ ret = []
84
+ data[:aliases].each do |rid, aliases|
85
+ aliases.each do |al|
86
+ ret << {
87
+ :alias => al,
88
+ :rid => rid
89
+ }
90
+ end
91
+ end
92
+
93
+ ret
94
+ end
95
+
96
+ ## Fetch data from one resource
97
+ def fetch(rid)
98
+ do_rpc({:id=>1,
99
+ :procedure=>:info,
100
+ :arguments=>[rid, {}],
101
+ })
102
+ end
103
+
104
+ ## Remove a resource by RID
105
+ def remove(rid)
106
+ do_rpc({:id=>1,
107
+ :procedure=>:drop,
108
+ :arguments=>[rid]
109
+ })
110
+ end
111
+
112
+ ## Create a new resource in the prodcut
113
+ def create(alias_id, format=:string)
114
+ raise "Alias cannot be nil" if alias_id.nil?
115
+ # create then map.
116
+ rid = do_rpc({:id=>1,
117
+ :procedure=>:create,
118
+ :arguments=>[:dataport,
119
+ {:format=>format,
120
+ :name=>alias_id,
121
+ :retention=>{:count=>1,:duration=>:infinity}
122
+ }
123
+ ]
124
+ })
125
+ return rid unless not rid.kind_of?(String) or rid.match(/\p{XDigit}{40}/)
126
+
127
+ do_rpc({:id=>1,
128
+ :procedure=>:map,
129
+ :arguments=>[:alias, rid, alias_id]
130
+ })
131
+ end
132
+
133
+ ## Upload a resource.
134
+ # this is for SyncUpDown
135
+ # @param modify Bool: True if item exists already and this is changing it
136
+ def upload(src, item, modify)
137
+ if modify then
138
+ # this is usually a format change, which can only be set on create.
139
+ # So delete then create.
140
+ remove(item[:rid])
141
+ end
142
+ r = create(item[:alias], item[:format])
143
+ raise "Create Failed: #{r}" unless r.nil?
144
+ end
145
+
146
+ ## Use alias for doing sync compares
147
+ # (The RID will change if destroyed and recreated.)
148
+ def synckey(item)
149
+ item[:alias]
150
+ end
151
+
152
+ ##
153
+ #
154
+ def tolocalpath(into, item)
155
+ into
156
+ end
157
+
158
+ ## Get a local list of items from the single file
159
+ def localitems(from)
160
+ from = Pathname.new(from) unless from.kind_of? Pathname
161
+ if not from.exist? then
162
+ say_warning "Skipping missing #{from.to_s}"
163
+ return []
164
+ end
165
+ unless from.file? then
166
+ say_warning "Cannot read from #{from.to_s}"
167
+ return []
168
+ end
169
+
170
+ here = []
171
+ from.open {|io| here = YAML.load(io) }
172
+ return [] if here == false
173
+
174
+ if here.kind_of?(Hash) and here.has_key?('resources') then
175
+ here['resources'].map{|i| Hash.transform_keys_to_symbols(i)}
176
+ else
177
+ []
178
+ end
179
+ end
180
+
181
+ def download(local, item)
182
+ # needs to append/merge with file
183
+ # for now, we'll read, modify, write
184
+ data = fetch(item[:rid])
185
+ item[:format] = data[:description][:format]
186
+
187
+ here = []
188
+ if local.exist? then
189
+ local.open('rb') {|io| here = YAML.load(io)}
190
+ here = [] if here == false
191
+ if here.kind_of?(Hash) and here.has_key?('resources') then
192
+ here = here['resources'].map{|i| Hash.transform_keys_to_symbols(i)}
193
+ else
194
+ here = []
195
+ end
196
+ end
197
+ here.delete_if do |i|
198
+ i[:alias] == item[:alias]
199
+ end
200
+ here << item.reject{|k,v| k==:synckey or k==:rid}
201
+ here.map!{|i| Hash.transform_keys_to_strings(i)}
202
+ local.open('wb') do |io|
203
+ io << {'resources'=>here}.to_yaml
204
+ end
205
+ end
206
+
207
+ def removelocal(dest, item)
208
+ # needs to append/merge with file
209
+ # for now, we'll read, modify, write
210
+ here = []
211
+ if dest.exist? then
212
+ dest.open('rb') {|io| here = YAML.load(io)}
213
+ here = [] if here == false
214
+ if here.kind_of?(Hash) and here.has_key?('resources') then
215
+ here = here['resources'].map{|i| Hash.transform_keys_to_symbols(i)}
216
+ else
217
+ here = []
218
+ end
219
+ end
220
+ here.delete_if do |it|
221
+ it[:alias] == item[:alias]
222
+ end
223
+ here.map!{|i| Hash.transform_keys_to_strings(i)}
224
+ dest.open('wb') do|io|
225
+ io << {'resources'=>here}.to_yaml
226
+ end
227
+ end
228
+
229
+ ##
230
+ # True if itemA and itemB are different
231
+ def docmp(itemA, itemB)
232
+ itemA[:alias] == itemB[:alias] and itemA[:format] == itemB[:format]
233
+ end
234
+
235
+ end
236
+ SyncRoot.add('specs', ProductResources, 'P', %{Product Specification})
237
+
238
+ end
239
+ # vim: set ai et sw=2 ts=2 :
@@ -11,11 +11,17 @@ module MrMurano
11
11
  @pid = $cfg['product.id']
12
12
  raise "No Product ID!" if @pid.nil?
13
13
  @uriparts = [:product, @pid]
14
+ @locationbase = $cfg['location.base']
15
+ @location = nil
14
16
  end
15
17
 
16
18
  include Http
17
19
  include Verbose
18
20
 
21
+ ## Generate an endpoint in Murano
22
+ # Uses the uriparts and path
23
+ # @param path String: any additional parts for the URI
24
+ # @return URI: The full URI for this enpoint.
19
25
  def endPoint(path='')
20
26
  parts = ['https:/', $cfg['net.host'], 'api:1'] + @uriparts
21
27
  s = parts.map{|v| v.to_s}.join('/')
@@ -24,18 +30,25 @@ module MrMurano
24
30
  end
25
31
 
26
32
  class Product < ProductBase
33
+ ## Get info about the product
27
34
  def info
28
35
  get('/info')
29
36
  end
30
37
 
38
+ ## List enabled devices
31
39
  def list(offset=0, limit=50)
32
40
  get("/device/?offset=#{offset}&limit=#{limit}")
33
41
  end
34
42
 
43
+ ## Enable a serial number
44
+ # This creates the device and opens the activation window.
35
45
  def enable(sn)
36
46
  post("/device/#{sn.to_s}")
37
47
  end
38
48
 
49
+ ## Upload a spec file.
50
+ #
51
+ # Note that this will fail if any of the resources already exist.
39
52
  def update(specFile)
40
53
  specFile = Pathname.new(specFile) unless specFile.kind_of? Pathname
41
54
 
@@ -53,10 +66,45 @@ module MrMurano
53
66
  ret
54
67
  end
55
68
 
69
+ ## Write a value to an alias on a device
56
70
  def write(sn, values)
57
71
  post("/write/#{sn}", values)
58
72
  end
59
73
 
74
+ ## Converts an exoline style spec file into a Murano style one
75
+ # @param fin IO: IO Stream to read from
76
+ # @return String: Converted yaml data
77
+ def convertit(fin)
78
+ specOut = {'resources'=>[]}
79
+ spec = YAML.load(fin)
80
+ if spec.has_key?('dataports') and spec['dataports'].kind_of?(Array) then
81
+ dps = spec['dataports'].map do |dp|
82
+ dp.delete_if{|k,v| k != 'alias' and k != 'format' and k != 'initial'}
83
+ dp['format'] = 'string' if (dp['format']||'')[0..5] == 'string'
84
+ dp
85
+ end
86
+ specOut['resources'] = dps
87
+ else
88
+ raise "No dataports section found, or not an array"
89
+ end
90
+ specOut
91
+ end
92
+
93
+ ## Converts an exoline style spec file into a Murano style one
94
+ # @param specFile String: Path to file or '-' for stdin
95
+ # @return String: Converted yaml data
96
+ def convert(specFile)
97
+ if specFile == '-' then
98
+ convertit($stdin).to_yaml
99
+ else
100
+ specFile = Pathname.new(specFile) unless specFile.kind_of? Pathname
101
+ out = ''
102
+ specFile.open() do |fin|
103
+ out = convertit(fin).to_yaml
104
+ end
105
+ out
106
+ end
107
+ end
60
108
  end
61
109
 
62
110
  ##
@@ -119,7 +167,7 @@ module MrMurano
119
167
  case resp
120
168
  when Net::HTTPSuccess
121
169
  if block_given? then
122
- resp.read_body &block
170
+ resp.read_body(&block)
123
171
  else
124
172
  resp.read_body do |chunk|
125
173
  $stdout.write chunk
@@ -136,7 +184,8 @@ module MrMurano
136
184
 
137
185
  ## Upload data for content item
138
186
  # TODO: add support for passing in IOStream
139
- def upload(id, path)
187
+ # @param modify Bool: True if item exists already and this is changing it
188
+ def upload(id, path, modify=false)
140
189
  path = Pathname.new(path) unless path.kind_of? Pathname
141
190
 
142
191
  mime = MIME::Types.type_for(path.to_s)[0] || MIME::Types["application/octet-stream"][0]
@@ -0,0 +1,81 @@
1
+ require 'yaml'
2
+ require 'json'
3
+ require 'MrMurano/Solution'
4
+
5
+ module MrMurano
6
+ class Cors < SolutionBase
7
+ def initialize
8
+ super
9
+ @uriparts << 'cors'
10
+ @location = $cfg['location.cors']
11
+ end
12
+
13
+ def list()
14
+ data = fetch()
15
+ data[:id] = 'cors'
16
+ [data]
17
+ end
18
+
19
+ def fetch(id=nil, &block)
20
+ ret = get()
21
+ data = JSON.parse(ret[:cors], @json_opts)
22
+ # XXX cors is a JSON encoded string. That seems weird. keep an eye on this.
23
+ if block_given? then
24
+ yield Hash.transform_keys_to_strings(data).to_yaml
25
+ else
26
+ data
27
+ end
28
+ end
29
+
30
+ def remove(id)
31
+ # Not really anything to do here. Return to defaults? maybe?
32
+ end
33
+
34
+ ##
35
+ # Upload CORS
36
+ # :local path to file to push
37
+ # :remote hash of method and endpoint path (ignored for now)
38
+ # @param modify Bool: True if item exists already and this is changing it
39
+ def upload(local, remote, modify=false)
40
+ remote.reject!{|k,v| k==:synckey or k==:bundled or k==:id}
41
+ put('', remote)
42
+ end
43
+
44
+ def tolocalpath(into, item)
45
+ into
46
+ end
47
+
48
+ def removelocal(dest, item)
49
+ # this is a nop.
50
+ end
51
+ #
52
+ def localitems(from)
53
+ from = Pathname.new(from) unless from.kind_of? Pathname
54
+ if not from.exist? then
55
+ warning "Skipping missing #{from.to_s}"
56
+ return []
57
+ end
58
+ unless from.file? then
59
+ warning "Cannot read from #{from.to_s}"
60
+ return []
61
+ end
62
+
63
+ here = {}
64
+ from.open {|io| here = YAML.load(io) }
65
+ return [] if here == false
66
+
67
+ here[:id] = 'cors'
68
+ [ Hash.transform_keys_to_symbols(here) ]
69
+ end
70
+
71
+ ##
72
+ # True if itemA and itemB are different
73
+ def docmp(itemA, itemB)
74
+ itemA != itemB
75
+ end
76
+
77
+ end
78
+ SyncRoot.add('cors', Cors, 'Z', %{CORS settings})
79
+ end
80
+
81
+ # vim: set ai et sw=2 ts=2 :
@@ -39,7 +39,8 @@ module MrMurano
39
39
  # Upload endpoint
40
40
  # :local path to file to push
41
41
  # :remote hash of method and endpoint path
42
- def upload(local, remote)
42
+ # @param modify Bool: True if item exists already and this is changing it
43
+ def upload(local, remote, modify)
43
44
  local = Pathname.new(local) unless local.kind_of? Pathname
44
45
  raise "no file" unless local.exist?
45
46
 
@@ -75,9 +76,10 @@ module MrMurano
75
76
  end
76
77
 
77
78
  def tolocalname(item, key)
78
- name = item[:method].downcase
79
- name << '_'
80
- name << item[:path].gsub(/\//, '-')
79
+ name = ''
80
+ name << item[:path].split('/').reject{|i|i.empty?}.join('-')
81
+ name << '.'
82
+ name << item[:method].downcase
81
83
  name << '.lua'
82
84
  end
83
85
 
@@ -109,5 +111,7 @@ module MrMurano
109
111
  end
110
112
 
111
113
  end
114
+
115
+ SyncRoot.add('endpoints', Endpoint, 'A', %{Endpoints}, true)
112
116
  end
113
117
  # vim: set ai et sw=2 ts=2 :
@@ -30,7 +30,7 @@ module MrMurano
30
30
  case resp
31
31
  when Net::HTTPSuccess
32
32
  if block_given? then
33
- resp.read_body &block
33
+ resp.read_body(&block)
34
34
  else
35
35
  resp.read_body do |chunk|
36
36
  $stdout.write chunk
@@ -62,7 +62,8 @@ module MrMurano
62
62
 
63
63
  ##
64
64
  # Upload a file
65
- def upload(local, remote)
65
+ # @param modify Bool: True if item exists already and this is changing it
66
+ def upload(local, remote, modify)
66
67
  local = Pathname.new(local) unless local.kind_of? Pathname
67
68
 
68
69
  uri = endPoint('upload' + remote[:path])
@@ -161,5 +162,6 @@ module MrMurano
161
162
  end
162
163
 
163
164
  end
165
+ SyncRoot.add('files', File, 'S', %{Static Files}, true)
164
166
  end
165
167
  # vim: set ai et sw=2 ts=2 :