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
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 :