MuranoCLI 2.2.4 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (159) hide show
  1. checksums.yaml +4 -4
  2. data/.agignore +3 -0
  3. data/.gitignore +18 -1
  4. data/.rubocop.yml +222 -0
  5. data/.trustme.sh +185 -0
  6. data/.trustme.vim +24 -0
  7. data/Gemfile +23 -4
  8. data/LICENSE.txt +1 -1
  9. data/MuranoCLI.gemspec +43 -8
  10. data/README.markdown +9 -11
  11. data/Rakefile +187 -143
  12. data/TODO.taskpaper +2 -2
  13. data/bin/murano +51 -52
  14. data/docs/basic_example.rst +436 -0
  15. data/docs/completions/murano_completion-bash +3484 -0
  16. data/docs/demo.md +32 -32
  17. data/docs/develop.rst +391 -0
  18. data/lib/MrMurano.rb +21 -7
  19. data/lib/MrMurano/Account.rb +159 -174
  20. data/lib/MrMurano/Business.rb +381 -0
  21. data/lib/MrMurano/Config-Migrate.rb +32 -26
  22. data/lib/MrMurano/Config.rb +407 -128
  23. data/lib/MrMurano/Content.rb +191 -0
  24. data/lib/MrMurano/Gateway.rb +489 -0
  25. data/lib/MrMurano/Keystore.rb +48 -0
  26. data/lib/MrMurano/Passwords.rb +103 -0
  27. data/lib/MrMurano/ProjectFile.rb +121 -79
  28. data/lib/MrMurano/ReCommander.rb +114 -10
  29. data/lib/MrMurano/Setting.rb +90 -0
  30. data/lib/MrMurano/Solution-ServiceConfig.rb +89 -45
  31. data/lib/MrMurano/Solution-Services.rb +461 -166
  32. data/lib/MrMurano/Solution-Users.rb +70 -31
  33. data/lib/MrMurano/Solution.rb +372 -13
  34. data/lib/MrMurano/SolutionId.rb +73 -0
  35. data/lib/MrMurano/SyncRoot.rb +137 -0
  36. data/lib/MrMurano/SyncUpDown.rb +594 -284
  37. data/lib/MrMurano/Webservice-Cors.rb +71 -0
  38. data/lib/MrMurano/Webservice-Endpoint.rb +234 -0
  39. data/lib/MrMurano/Webservice-File.rb +193 -0
  40. data/lib/MrMurano/Webservice.rb +51 -0
  41. data/lib/MrMurano/commands.rb +18 -15
  42. data/lib/MrMurano/commands/business.rb +300 -6
  43. data/lib/MrMurano/commands/completion-bash.erb +166 -0
  44. data/lib/MrMurano/commands/{zshcomplete.erb → completion-zsh.erb} +0 -0
  45. data/lib/MrMurano/commands/completion.rb +76 -39
  46. data/lib/MrMurano/commands/config.rb +108 -44
  47. data/lib/MrMurano/commands/content.rb +115 -72
  48. data/lib/MrMurano/commands/cors.rb +29 -14
  49. data/lib/MrMurano/commands/devices.rb +286 -0
  50. data/lib/MrMurano/commands/domain.rb +52 -12
  51. data/lib/MrMurano/commands/gb.rb +24 -9
  52. data/lib/MrMurano/commands/globals.rb +64 -0
  53. data/lib/MrMurano/commands/init.rb +377 -155
  54. data/lib/MrMurano/commands/keystore.rb +92 -82
  55. data/lib/MrMurano/commands/link.rb +300 -0
  56. data/lib/MrMurano/commands/login.rb +74 -11
  57. data/lib/MrMurano/commands/logs.rb +63 -32
  58. data/lib/MrMurano/commands/mock.rb +57 -29
  59. data/lib/MrMurano/commands/password.rb +57 -39
  60. data/lib/MrMurano/commands/postgresql.rb +127 -94
  61. data/lib/MrMurano/commands/settings.rb +203 -0
  62. data/lib/MrMurano/commands/show.rb +79 -38
  63. data/lib/MrMurano/commands/solution.rb +423 -5
  64. data/lib/MrMurano/commands/solution_picker.rb +547 -0
  65. data/lib/MrMurano/commands/status.rb +195 -61
  66. data/lib/MrMurano/commands/sync.rb +78 -39
  67. data/lib/MrMurano/commands/timeseries.rb +71 -55
  68. data/lib/MrMurano/commands/tsdb.rb +113 -87
  69. data/lib/MrMurano/commands/usage.rb +57 -15
  70. data/lib/MrMurano/hash.rb +100 -10
  71. data/lib/MrMurano/http.rb +187 -43
  72. data/lib/MrMurano/makePretty.rb +16 -14
  73. data/lib/MrMurano/optparse.rb +2178 -0
  74. data/lib/MrMurano/progress.rb +138 -0
  75. data/lib/MrMurano/schema/resource-v1.0.0.yaml +32 -0
  76. data/lib/MrMurano/template/projectFile.murano.erb +16 -13
  77. data/lib/MrMurano/verbosing.rb +166 -29
  78. data/lib/MrMurano/version.rb +30 -1
  79. data/spec/Account-Passwords_spec.rb +21 -4
  80. data/spec/Account_spec.rb +69 -146
  81. data/spec/Business_spec.rb +290 -0
  82. data/spec/ConfigFile_spec.rb +1 -0
  83. data/spec/ConfigMigrate_spec.rb +12 -8
  84. data/spec/Config_spec.rb +40 -34
  85. data/spec/Content_spec.rb +363 -0
  86. data/spec/GatewayBase_spec.rb +54 -0
  87. data/spec/GatewayDevice_spec.rb +321 -0
  88. data/spec/GatewayResource_spec.rb +266 -0
  89. data/spec/GatewaySettings_spec.rb +120 -0
  90. data/spec/Http_spec.rb +18 -8
  91. data/spec/Mock_spec.rb +2 -2
  92. data/spec/ProjectFile_spec.rb +25 -14
  93. data/spec/Setting_spec.rb +110 -0
  94. data/spec/Solution-ServiceConfig_spec.rb +44 -5
  95. data/spec/Solution-ServiceEventHandler_spec.rb +23 -14
  96. data/spec/Solution-ServiceModules_spec.rb +47 -37
  97. data/spec/Solution-UsersRoles_spec.rb +10 -8
  98. data/spec/Solution_spec.rb +17 -8
  99. data/spec/SyncRoot_spec.rb +46 -20
  100. data/spec/SyncUpDown_spec.rb +437 -201
  101. data/spec/Verbosing_spec.rb +12 -4
  102. data/spec/{Solution-Cors_spec.rb → Webservice-Cors_spec.rb} +23 -20
  103. data/spec/{Solution-Endpoint_spec.rb → Webservice-Endpoint_spec.rb} +43 -41
  104. data/spec/{Solution-File_spec.rb → Webservice-File_spec.rb} +44 -33
  105. data/spec/Webservice-Setting_spec.rb +89 -0
  106. data/spec/_workspace.rb +4 -4
  107. data/spec/cmd_business_spec.rb +9 -4
  108. data/spec/cmd_common.rb +44 -1
  109. data/spec/cmd_content_spec.rb +43 -17
  110. data/spec/cmd_cors_spec.rb +4 -4
  111. data/spec/cmd_device_spec.rb +61 -16
  112. data/spec/cmd_domain_spec.rb +29 -6
  113. data/spec/cmd_init_spec.rb +281 -126
  114. data/spec/cmd_keystore_spec.rb +3 -3
  115. data/spec/cmd_link_spec.rb +98 -0
  116. data/spec/cmd_password_spec.rb +1 -1
  117. data/spec/cmd_setting_application_spec.rb +260 -0
  118. data/spec/cmd_setting_product_spec.rb +220 -0
  119. data/spec/cmd_status_spec.rb +223 -114
  120. data/spec/cmd_syncdown_spec.rb +115 -35
  121. data/spec/cmd_syncup_spec.rb +68 -15
  122. data/spec/cmd_usage_spec.rb +35 -8
  123. data/spec/fixtures/dumped_config +6 -4
  124. data/spec/fixtures/gateway_resource_files/resources.notyaml +12 -0
  125. data/spec/fixtures/gateway_resource_files/resources.yaml +13 -0
  126. data/spec/fixtures/gateway_resource_files/resources_invalid.yaml +13 -0
  127. data/spec/fixtures/mrmuranorc_deleted_bob +0 -2
  128. data/spec/fixtures/product_spec_files/lightbulb.yaml +20 -13
  129. data/spec/fixtures/{syncable_content → syncable_conflict}/services/devdata.lua +1 -1
  130. data/spec/fixtures/{syncable_content → syncable_conflict}/services/timers.lua +0 -0
  131. data/spec/spec_helper.rb +5 -0
  132. metadata +262 -171
  133. data/bin/mr +0 -8
  134. data/lib/MrMurano/Product-1P-Device.rb +0 -145
  135. data/lib/MrMurano/Product-Resources.rb +0 -205
  136. data/lib/MrMurano/Product.rb +0 -358
  137. data/lib/MrMurano/Solution-Cors.rb +0 -47
  138. data/lib/MrMurano/Solution-Endpoint.rb +0 -191
  139. data/lib/MrMurano/Solution-File.rb +0 -166
  140. data/lib/MrMurano/commands/assign.rb +0 -57
  141. data/lib/MrMurano/commands/businessList.rb +0 -45
  142. data/lib/MrMurano/commands/product.rb +0 -14
  143. data/lib/MrMurano/commands/productCreate.rb +0 -39
  144. data/lib/MrMurano/commands/productDelete.rb +0 -33
  145. data/lib/MrMurano/commands/productDevice.rb +0 -87
  146. data/lib/MrMurano/commands/productDeviceIdCmds.rb +0 -89
  147. data/lib/MrMurano/commands/productList.rb +0 -45
  148. data/lib/MrMurano/commands/productWrite.rb +0 -27
  149. data/lib/MrMurano/commands/solutionCreate.rb +0 -41
  150. data/lib/MrMurano/commands/solutionDelete.rb +0 -34
  151. data/lib/MrMurano/commands/solutionList.rb +0 -45
  152. data/spec/ProductBase_spec.rb +0 -113
  153. data/spec/ProductContent_spec.rb +0 -162
  154. data/spec/ProductResources_spec.rb +0 -329
  155. data/spec/Product_1P_Device_spec.rb +0 -202
  156. data/spec/Product_1P_RPC_spec.rb +0 -175
  157. data/spec/Product_spec.rb +0 -153
  158. data/spec/Solution-ServiceDevice_spec.rb +0 -176
  159. data/spec/cmd_assign_spec.rb +0 -51
@@ -1,20 +1,30 @@
1
+ # Last Modified: 2017.08.16 /coding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ # Copyright © 2016-2017 Exosite LLC.
5
+ # License: MIT. See LICENSE.txt.
6
+ # vim:tw=0:ts=2:sw=2:et:ai
7
+
8
+ require 'MrMurano/ReCommander'
1
9
  require 'MrMurano/Solution-ServiceConfig'
2
10
 
3
11
  module MrMurano
4
12
  class Postgresql < ServiceConfig
5
- def initialize
13
+ def initialize(sid=nil)
14
+ # FIXME/2017-07-03: What soln types have PSQLs?
15
+ @solntype = 'application.id'
6
16
  super
7
- @serviceName = 'postgresql'
17
+ @service_name = 'postgresql'
8
18
  end
9
19
 
10
20
  def query(query, params=nil)
11
- aqr = {:sql=>query}
21
+ aqr = { sql: query }
12
22
  aqr[:parameters] = params unless params.nil?
13
23
  call(:query, :post, aqr)
14
24
  end
15
25
 
16
26
  def queries(query, params=nil)
17
- aqr = {:sql=>query}
27
+ aqr = { sql: query }
18
28
  aqr[:parameters] = params unless params.nil?
19
29
  call(:queries, :post, aqr)
20
30
  end
@@ -22,163 +32,186 @@ module MrMurano
22
32
  end
23
33
 
24
34
  command :postgresql do |c|
25
- c.syntax = %{murano postgresql <SQL Commands>}
26
- c.summary = %{Query the relational database}
27
- c.description = %{Query the relational database
28
-
29
- Queries can include $# escapes that are filled from the --param option.
30
- }
31
-
32
- c.option '--param LIST',Array, %{Values to fill $# with}
33
- c.option '-f', '--file FILE', %{File of SQL commands}
34
- c.option '-o', '--output FILE', %{Download to file instead of STDOUT}
35
+ c.syntax = %(murano postgresql <SQL Commands>)
36
+ c.summary = %(Query the relational database)
37
+ c.description = %(
38
+ Query the relational database.
39
+
40
+ Queries can include $# escapes that are filled from the --param option.
41
+ ).strip
42
+
43
+ c.option '--param LIST', Array, %(Values to fill $# with)
44
+ c.option '-f', '--file FILE', %(File of SQL commands)
45
+ c.option '-o', '--output FILE', %(Download to file instead of STDOUT)
46
+
47
+ c.example %(murano postgresql 'select * from bob'), %(Run a SQL command)
48
+ c.example(
49
+ %(murano postgresql 'select * from prices' -c outformat=csv -o prices.csv),
50
+ %(Download all values in prices to a CSV file.)
51
+ )
52
+ c.example(
53
+ %(murano postgresql 'INSERT INTO prices (price, item) VALUES ($1,$2)' --param 1.24,Food),
54
+ %(Insert using parameters.)
55
+ )
56
+ c.example %(murano postgresql -f cmds.sql), %(Run multiple commands from a file)
57
+
58
+ c.action do |args, options|
59
+ # SKIP: c.verify_arg_count!(args)
35
60
 
36
- c.example %{murano postgresql 'select * from bob'}, %{Run a SQL command}
37
- c.example %{murano postgresql 'select * from prices' -c outformat=csv -o prices.csv}, %{Download all values in prices to a CSV file.}
38
- c.example %{murano postgresql 'INSERT INTO prices (price, item) VALUES ($1,$2)' --param 1.24,Food}, %{Insert using parameters.}
39
- c.example %{murano postgresql -f cmds.sql}, %{Run multiple commands from a file}
40
-
41
- c.action do |args,options|
42
61
  pg = MrMurano::Postgresql.new
43
- if options.file then
62
+ if options.file
44
63
  sqls = File.read(options.file)
45
-
46
64
  ret = pg.queries(sqls, options.param)
47
65
  else
48
66
  ret = pg.query(args.join(' '), options.param)
49
67
  end
50
68
 
51
- unless ret[:error].nil? then
69
+ exit 1 if ret.nil?
70
+ unless ret[:error].nil?
52
71
  pg.error "Returned error: #{ret[:error]}"
53
72
  exit 1
54
73
  end
55
74
 
56
- io=nil
57
- if options.output then
58
- io = File.open(options.output, 'w')
59
- end
75
+ io = nil
76
+ io = File.open(options.output, 'w') if options.output
60
77
 
61
78
  pg.outf(ret, io) do |dd, ios|
62
79
  dd = dd[:result]
63
- pg.tabularize({
64
- :headers=>dd[:columns],
65
- :rows=>dd[:rows]
66
- }, ios)
80
+ # Look for date cells and pretty them. (a Hash with specific fields)
81
+ # All others, call to_s
82
+ rows = dd[:rows].map do |row|
83
+ row.map do |cell|
84
+ if cell.is_a?(Hash) && cell.keys.sort == %i[day hour min month sec usec year]
85
+ t = Time.gm(
86
+ cell[:year], cell[:month], cell[:day], cell[:hour], cell[:min], cell[:sec], cell[:usec]
87
+ )
88
+ t.getlocal.strftime('%F %T.%6N %z')
89
+ else
90
+ cell.to_s
91
+ end
92
+ end
93
+ end
94
+ pg.tabularize(
95
+ {
96
+ headers: dd[:columns],
97
+ rows: rows,
98
+ },
99
+ ios
100
+ )
67
101
  end
68
102
  io.close unless io.nil?
69
-
70
103
  end
71
104
  end
72
105
 
73
106
  command 'postgresql migrate' do |c|
74
- c.syntax = %{murano postgresql migrate (up|down) <level>}
75
- c.summary = %{Run database migration scripts.}
76
- c.description = %{Run database migration scripts.
107
+ c.syntax = %(murano postgresql migrate (up|down) [<level>])
108
+ c.summary = %(Run database migration scripts.)
109
+ c.description = %(
110
+ Run database migration scripts.
77
111
 
78
- The names of the script files must be in the "<level>-<name>-<up|down>.sql"
79
- format. Each file is a series of Postgres SQL commands.
112
+ The names of the script files must be in the "<level>-<name>-<up|down>.sql"
113
+ format. Each file is a series of Postgres SQL commands.
80
114
 
81
- The current version of the migrations (last <level> ran) will be stored in an
82
- extra table in your database. (__murano_cli__.migrate_version)
115
+ The current version of the migrations (last <level> ran) will be stored in an
116
+ extra table in your database. (__murano_cli__.migrate_version)
117
+ ).strip
83
118
 
84
- }
119
+ c.option '--dir DIR', %(Directory where migrations live)
85
120
 
86
- c.option '--dir DIR', %{Directory where migrations live}
121
+ c.example %(murano postgresql migrate up), %(Run migrations up to largest version.)
122
+ c.example %(murano postgresql migrate up 2), %(Run migrations up to version 2.)
123
+ c.example %(murano postgresql migrate down 1), %(Run migrations down to version 1.)
124
+ c.example %(murano postgresql migrate down 0), %(Run migrations down to version 0.)
87
125
 
88
- c.example %{murano postgresql migrate up}, %{Run migrations up to largest version.}
89
- c.example %{murano postgresql migrate up 2}, %{Run migrations up to version 2.}
90
- c.example %{murano postgresql migrate down 1}, %{Run migrations down to version 1.}
91
- c.example %{murano postgresql migrate down 0}, %{Run migrations down to version 0.}
126
+ c.action do |args, options|
127
+ c.verify_arg_count!(args, 2, ['Missing direction'])
128
+ options.default(dir: File.join($cfg['location.base'], ($cfg['postgresql.migrations_dir'] || '')))
92
129
 
93
- c.action do |args,options|
94
- options.default :dir => File.join($cfg['location.base'], $cfg['postgresql.migrations_dir'])
130
+ pg = MrMurano::Postgresql.new
95
131
 
96
132
  direction = args.shift
97
- if direction =~ /down/i then
133
+ if direction =~ /down/i
98
134
  direction = 'down'
99
- else
135
+ elsif direction =~ /up/i
100
136
  direction = 'up'
137
+ else
138
+ pg.error "Unrecogized direction: ‘#{direction}’"
139
+ exit 1
101
140
  end
102
141
 
103
142
  want_version = args.first
104
143
 
105
- pg = MrMurano::Postgresql.new
106
-
107
144
  # get current version of DB.
108
- ret = pg.queries %{
109
- CREATE SCHEMA IF NOT EXISTS __murano_cli__;
110
- CREATE TABLE IF NOT EXISTS __murano_cli__.migrate_version (version integer);
111
- SELECT version FROM __murano_cli__.migrate_version ORDER BY version DESC;
112
- }.gsub(/^\s+/,'')
113
- unless ret[:error].nil? then
145
+ ret = pg.queries %(
146
+ CREATE SCHEMA IF NOT EXISTS __murano_cli__;
147
+ CREATE TABLE IF NOT EXISTS __murano_cli__.migrate_version (version integer);
148
+ SELECT version FROM __murano_cli__.migrate_version ORDER BY version DESC;
149
+ ).gsub(/^\s+/, '')
150
+ unless ret[:error].nil?
114
151
  pp ret
115
152
  exit 1
116
153
  end
117
154
  pg.debug "create/select: #{ret}"
118
- current_version = (((((ret[:result] or []).last or {})[:rows] or []).first or []).first or 0).to_i
155
+ current_version = (((((ret[:result] || []).last || {})[:rows] || []).first || []).first || 0).to_i
119
156
 
120
157
  # Get migrations
121
158
  migrations = Dir[File.join(options.dir, "*-#{direction}.sql")].sort
122
- if migrations.empty? then
123
- pg.error "No migrations to run."
159
+ if migrations.empty?
160
+ pg.error 'No migrations to run.'
124
161
  exit 1
125
162
  end
126
163
  migrations.reverse! if direction == 'down'
127
164
 
128
- if want_version.nil? then
129
- want_version, _ = File.basename(migrations.last).split('-')
130
- end
165
+ want_version, = File.basename(migrations.last).split('-') if want_version.nil?
131
166
  want_version = want_version.to_i
132
167
  pg.verbose "Will migrate from version #{current_version} to #{want_version}"
133
- if direction == 'down' then
134
- if want_version >= current_version then
135
- say "Nothing to do."
136
- exit 0
137
- end
138
- else
139
- if want_version <= current_version then
140
- say "Nothing to do."
168
+ if direction == 'down'
169
+ if want_version >= current_version
170
+ say 'Nothing to do.'
141
171
  exit 0
142
172
  end
173
+ elsif want_version <= current_version
174
+ say 'Nothing to do.'
175
+ exit 0
143
176
  end
144
177
 
145
178
  pg.debug "Migrations before: #{migrations}"
146
179
  # Select migrations between current and desired
147
180
  migrations.select! do |m|
148
- mvrs, _ = File.basename(m).split('-')
181
+ mvrs, = File.basename(m).split('-')
149
182
  mvrs = mvrs.to_i
150
- if direction == 'down' then
151
- mvrs <= current_version and mvrs > want_version
183
+ if direction == 'down'
184
+ mvrs <= current_version && mvrs > want_version
152
185
  else
153
- mvrs > current_version and mvrs <= want_version
186
+ mvrs > current_version && mvrs <= want_version
154
187
  end
155
188
  end
156
189
  pg.debug "Migrations after: #{migrations}"
157
190
 
158
191
  # Run migrations.
159
192
  migrations.each do |m|
160
- mvrs, _ = File.basename(m).split('-')
193
+ mvrs, = File.basename(m).split('-')
161
194
  pg.verbose "Running migration: #{File.basename(m)}"
162
- unless $cfg['tool.dry'] then
163
- pg.query 'BEGIN;'
164
- ret = pg.queries File.read(m)
165
- unless ret[:error].nil? then
166
- pg.query 'ROLLBACK;'
167
- pg.error "Migrations failed at level #{mvrs}"
168
- pg.error "Because: #{ret[:error]}"
169
- exit 5
170
- else
171
- if direction == 'down' then
172
- pg.queries %{DELETE FROM __murano_cli__.migrate_version WHERE version = #{mvrs};
173
- COMMIT;}.gsub(/^\s+/,'')
174
- else
175
- pg.queries %{INSERT INTO __murano_cli__.migrate_version values (#{mvrs});
176
- COMMIT;}.gsub(/^\s+/,'')
177
- end
178
- end
195
+ next if $cfg['tool.dry']
196
+ pg.query 'BEGIN;'
197
+ ret = pg.queries File.read(m)
198
+ if !ret[:error].nil?
199
+ pg.query 'ROLLBACK;'
200
+ pg.error "Migrations failed at level #{mvrs}"
201
+ pg.error "Because: #{ret[:error]}"
202
+ exit 5
203
+ elsif direction == 'down'
204
+ pg.queries %(
205
+ DELETE FROM __murano_cli__.migrate_version WHERE version = #{mvrs};
206
+ COMMIT;
207
+ ).gsub(/^\s+/, '')
208
+ else
209
+ pg.queries %(
210
+ INSERT INTO __murano_cli__.migrate_version values (#{mvrs});
211
+ COMMIT;
212
+ ).gsub(/^\s+/, '')
179
213
  end
180
214
  end
181
215
  end
182
216
  end
183
217
 
184
- # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,203 @@
1
+ require 'vine'
2
+ require 'yaml'
3
+ require 'MrMurano/hash'
4
+ require 'MrMurano/ReCommander'
5
+ require 'MrMurano/Setting'
6
+
7
+ command 'setting list' do |c|
8
+ c.syntax = %{murano setting list}
9
+ c.summary = %{List which services and settings are avalible.}
10
+ c.description = %{
11
+ List which services and settings are avalible.
12
+ }.strip
13
+ c.project_not_required = true
14
+
15
+ c.action do |args, options|
16
+ c.verify_arg_count!(args)
17
+
18
+ setting = MrMurano::Setting.new
19
+
20
+ ret = setting.list
21
+
22
+ dd = []
23
+ ret.each_pair { |k,v| v.each { |s| dd << "#{k}.#{s}" } }
24
+
25
+ setting.outf dd
26
+ end
27
+ end
28
+ alias_command 'settings list', 'setting list'
29
+
30
+ command 'setting read' do |c|
31
+ c.syntax = %{murano setting read <service>.<setting> [<sub-key>]}
32
+ c.summary = %{Read a setting on a Service}
33
+ c.description = %{
34
+ Read a setting on a Service.
35
+ }.strip
36
+
37
+ c.option '-o', '--output FILE', String, %{File to save output to}
38
+
39
+ c.action do |args, options|
40
+ c.verify_arg_count!(args, 2, ['Missing <service>.<setting>'])
41
+
42
+ setting = MrMurano::Setting.new
43
+
44
+ service, pref = args[0].split('.')
45
+ subkey = args[1]
46
+
47
+ ret = setting.read(service, pref)
48
+
49
+ ret = ret.access(subkey) unless subkey.nil?
50
+
51
+ io = nil
52
+ if options.output then
53
+ io = File.open(options.output, 'w')
54
+ end
55
+ setting.outf(ret, io)
56
+ io.close unless io.nil?
57
+ end
58
+ end
59
+
60
+ command 'setting write' do |c|
61
+ c.syntax = %{murano setting write <service>.<setting> <sub-key> [<value>...]}
62
+ c.summary = %{Write a setting on a Service}
63
+ c.description = %{
64
+ Write a setting on a Service, or just part of a setting.
65
+
66
+ if <value> is omitted on command line, then it is read from STDIN.
67
+
68
+ This always does a read-modify-write.
69
+
70
+ If a sub-key doesn't exist, that entire path will be created as dicts.
71
+ }.strip
72
+
73
+ c.option '--bool', %{Set Value type to boolean}
74
+ c.option '--num', %{Set Value type to number}
75
+ c.option '--string', %{Set Value type to string (this is default)}
76
+ c.option '--json', %{Value is parsed as JSON}
77
+ c.option '--array', %{Set Value type to array of strings}
78
+ c.option '--dict', %{Set Value type to a dictionary of strings}
79
+
80
+ c.option '--append', %{When sub-key is an array, append values instead of replacing}
81
+ c.option '--merge', %{When sub-key is a dict, merge values instead of replacing (child dicts are also merged)}
82
+
83
+ c.example %{murano setting write Gateway.protocol devmode --bool yes}, %{}
84
+ c.example %{murano setting write Gateway.identity_format options.length --int 24}, %{}
85
+
86
+ c.example %{murano setting write Webservice.cors methods --array HEAD GET POST}, %{}
87
+ c.example %{murano setting write Webservice.cors headers --append --array X-My-Token}, %{}
88
+
89
+ c.example %{murano setting write Webservice.cors --type=json - < }, %{}
90
+
91
+ c.action do |args, options|
92
+ c.verify_arg_count!(args, nil, ['Missing <service>.<setting>', 'Missing <sub-key>'])
93
+ options.default(
94
+ bool: false,
95
+ num: false,
96
+ string: true,
97
+ json: false,
98
+ array: false,
99
+ dict: false,
100
+ append: false,
101
+ merge: false,
102
+ )
103
+
104
+ service, pref = args.shift.split('.')
105
+ subkey = args.shift
106
+ value = args.first
107
+
108
+ setting = MrMurano::Setting.new
109
+
110
+ # If value is '-', pull from $stdin
111
+ if value.nil? and args.count == 0 then
112
+ value = $stdin.read
113
+ end
114
+
115
+ # Set value to correct type.
116
+ if options.bool then
117
+ if value =~ /(yes|y|true|t|1|on)/i then
118
+ value = true
119
+ elsif value =~ /(no|n|false|f|0|off)/i then
120
+ value = false
121
+ else
122
+ setting.error %{Value "#{value}" is not a bool type!}
123
+ exit 2
124
+ end
125
+ elsif options.num then
126
+ begin
127
+ value = Integer(value)
128
+ rescue Exception => e
129
+ setting.debug e.to_s
130
+ begin
131
+ value = Float(value)
132
+ rescue Exception => e
133
+ setting.error %{Value "#{value}" is not a number}
134
+ setting.debug e.to_s
135
+ exit 2
136
+ end
137
+ end
138
+ elsif options.json then
139
+ # We use the YAML parser since it will handle most common typos in json and
140
+ # product the intended output.
141
+ begin
142
+ value = YAML.load(value)
143
+ rescue Exception => e
144
+ setting.error %{Value not valid JSON (or YAML)}
145
+ setting.debug e.to_s
146
+ exit 2
147
+ end
148
+
149
+ elsif options.array then
150
+ # take remaining args as an array
151
+ value = args
152
+
153
+ elsif options.dict then
154
+ # take remaining args and convert to hash
155
+ begin
156
+ value = Hash.transform_keys_to_symbols(Hash[*args])
157
+ rescue ArgumentError => e
158
+ setting.error %{Odd number of arguments to dictionary}
159
+ setting.debug e.to_s
160
+ exit 2
161
+ rescue Exception => e
162
+ setting.error %{Cannot make dictionary from args}
163
+ setting.debug e.to_s
164
+ exit 2
165
+ end
166
+
167
+ elsif options.string then
168
+ value = value.to_s
169
+ else
170
+ # is a string.
171
+ value = value.to_s
172
+ end
173
+
174
+ ret = setting.read(service, pref)
175
+ setting.verbose %{Read value: #{ret}}
176
+
177
+ # modify and merge.
178
+ if options.append then
179
+ g = ret.access(subkey)
180
+ unless g.kind_of? Array then
181
+ setting.error %{Cannot append; "#{subkey}" is not an array.}
182
+ exit 3
183
+ end
184
+ g.push(*value)
185
+
186
+ elsif options.merge then
187
+ g = ret.access(subkey)
188
+ unless g.kind_of? Hash then
189
+ setting.error %{Cannot append; "#{subkey}" is not a dictionary.}
190
+ exit 3
191
+ end
192
+ g.deep_merge!(value)
193
+ else
194
+ ret.set(subkey, value)
195
+ end
196
+ setting.verbose %{Going to write composed value: #{ret}}
197
+
198
+ setting.write(service, pref, ret)
199
+ end
200
+ end
201
+
202
+ # vim: set ai et sw=2 ts=2 :
203
+