MuranoCLI 3.2.0.beta.5 → 3.2.0.beta.8
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.
- checksums.yaml +4 -4
- data/.ignore +22 -11
- data/dockers/Dockerfile.2.2.9 +2 -2
- data/dockers/Dockerfile.2.3.6 +2 -2
- data/dockers/Dockerfile.2.4.3 +2 -2
- data/dockers/Dockerfile.2.5.0 +2 -2
- data/dockers/Dockerfile.GemRelease +6 -6
- data/dockers/Dockerfile.m4 +4 -4
- data/dockers/README.rst +87 -19
- data/dockers/RELEASE.rst +1 -1
- data/dockers/docker-test.sh +4 -1
- data/{.trustme.plugin → docs/ci/.trustme.plugin} +5 -2
- data/{.trustme.sh → docs/ci/.trustme.sh} +64 -16
- data/lib/MrMurano/Business.rb +73 -0
- data/lib/MrMurano/Config.rb +4 -3
- data/lib/MrMurano/Keystore.rb +4 -0
- data/lib/MrMurano/ReCommander.rb +23 -0
- data/lib/MrMurano/Solution.rb +10 -0
- data/lib/MrMurano/SyncUpDown-Core.rb +94 -56
- data/lib/MrMurano/SyncUpDown-Item.rb +2 -0
- data/lib/MrMurano/Webservice-Endpoint.rb +8 -7
- data/lib/MrMurano/commands/business.rb +60 -0
- data/lib/MrMurano/commands/content.rb +7 -1
- data/lib/MrMurano/commands/cors.rb +1 -0
- data/lib/MrMurano/commands/devices.rb +1 -1
- data/lib/MrMurano/commands/element.rb +40 -14
- data/lib/MrMurano/commands/keystore.rb +8 -0
- data/lib/MrMurano/commands/logs.rb +1 -0
- data/lib/MrMurano/commands/network.rb +120 -0
- data/lib/MrMurano/commands/postgresql.rb +2 -0
- data/lib/MrMurano/commands/service.rb +5 -0
- data/lib/MrMurano/commands/settings.rb +3 -0
- data/lib/MrMurano/commands/show.rb +1 -0
- data/lib/MrMurano/commands/status.rb +1 -0
- data/lib/MrMurano/commands/sync.rb +2 -0
- data/lib/MrMurano/commands/timeseries.rb +9 -0
- data/lib/MrMurano/commands/tsdb.rb +4 -0
- data/lib/MrMurano/commands.rb +1 -0
- data/lib/MrMurano/variegated/ruby_dig.rb +11 -0
- data/lib/MrMurano/version.rb +1 -1
- data/spec/cmd_element_spec.rb +2 -2
- data/spec/fixtures/dumped_config +1 -0
- metadata +6 -5
- /data/{.trustme.vim → docs/ci/.trustme.vim} +0 -0
data/lib/MrMurano/ReCommander.rb
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
require 'optparse'
|
9
9
|
require 'MrMurano/optparse'
|
10
10
|
require 'MrMurano/verbosing'
|
11
|
+
require 'MrMurano/Business'
|
11
12
|
|
12
13
|
module MrMurano
|
13
14
|
class Hooked
|
@@ -51,6 +52,9 @@ module Commander
|
|
51
52
|
attr_accessor :prompt_if_logged_off
|
52
53
|
# A command sets subcmdgrouphelp if it's help.
|
53
54
|
attr_accessor :subcmdgrouphelp
|
55
|
+
# A command sets must_not_be_managed if its
|
56
|
+
# use is restricted to unmanaged solutions.
|
57
|
+
attr_accessor :must_not_be_managed
|
54
58
|
|
55
59
|
def verify_arg_count!(args, max_args=0, mandatory=[])
|
56
60
|
if !max_args.nil? && max_args.zero?
|
@@ -84,6 +88,8 @@ module Commander
|
|
84
88
|
hooked = MrMurano::Hooked.new(section)
|
85
89
|
hooked.check_run_pre_hook
|
86
90
|
|
91
|
+
verify_solutions_unmanaged!
|
92
|
+
|
87
93
|
begin
|
88
94
|
old_run_active_command
|
89
95
|
rescue LocalJumpError => _err
|
@@ -357,6 +363,23 @@ module Commander
|
|
357
363
|
puts mur_msg
|
358
364
|
exit 0
|
359
365
|
end
|
366
|
+
|
367
|
+
# (lb): I'm not a huge fan of mingling business logic with our
|
368
|
+
# Commander monkey patch, but it's a lot more readable that
|
369
|
+
# having every command make the call!
|
370
|
+
def verify_solutions_unmanaged!
|
371
|
+
return if $cfg['tool.skip-managed']
|
372
|
+
# (lb): All @exosite.com employees are welcome behind the curtain.
|
373
|
+
if $cfg['user.name'].end_with? "@exosite.com"
|
374
|
+
MrMurano::Verbose.verbose(
|
375
|
+
"Welcome behind the curtain, #{$cfg['user.name']}!"
|
376
|
+
)
|
377
|
+
return
|
378
|
+
end
|
379
|
+
# FIXME/LATER: (lb): The Element Author should also be allowed in.
|
380
|
+
return unless active_command.must_not_be_managed
|
381
|
+
MrMurano::Business.must_not_be_managed!
|
382
|
+
end
|
360
383
|
end
|
361
384
|
end
|
362
385
|
|
data/lib/MrMurano/Solution.rb
CHANGED
@@ -220,6 +220,10 @@ module MrMurano
|
|
220
220
|
@meta[:domain]
|
221
221
|
end
|
222
222
|
|
223
|
+
def managed?
|
224
|
+
@meta[:managed]
|
225
|
+
end
|
226
|
+
|
223
227
|
def pretty_desc(add_type: false, raw_url: false)
|
224
228
|
# [lb] would normally put presentation code elsewhere (i.e., model
|
225
229
|
# classes should not be formatting output), but this seems okay.
|
@@ -297,6 +301,12 @@ module MrMurano
|
|
297
301
|
def name_validate_help
|
298
302
|
''
|
299
303
|
end
|
304
|
+
|
305
|
+
def must_not_be_managed!
|
306
|
+
return unless managed?
|
307
|
+
error 'Specified command cannot be run against managed solution.'
|
308
|
+
exit 1
|
309
|
+
end
|
300
310
|
end
|
301
311
|
|
302
312
|
class Application < Solution
|
@@ -161,26 +161,89 @@ module MrMurano
|
|
161
161
|
# @param asdown [Boolean] Direction/prespective of diff
|
162
162
|
# @return [String] The diff output
|
163
163
|
def dodiff(merged, local, _there=nil, options={})
|
164
|
+
localname = dodiff_resolve_localname(merged)
|
165
|
+
trmt, tlcl = dodiff_tempfile_paths(localname)
|
166
|
+
dodiff_header_aware(merged, trmt, tlcl, options)
|
167
|
+
end
|
168
|
+
|
169
|
+
def dodiff_resolve_localname(merged)
|
164
170
|
localname = tolocalname(merged, @itemkey)
|
165
171
|
# MUR-6488: Beware nested files, e.g., /tmp/js/script.js will
|
166
172
|
# not work, because /tmp/js does not exist!
|
167
173
|
# First, remove the leading path delimiter.
|
168
174
|
localname = localname.gsub(/^#{::File::SEPARATOR}*/, '')
|
169
175
|
# Next, replace remaining delimiters with a dot.
|
170
|
-
localname
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
176
|
+
localname.tr(::File::SEPARATOR, '.')
|
177
|
+
end
|
178
|
+
|
179
|
+
def dodiff_tempfile_paths(localname)
|
180
|
+
# (lb): Not always Lua, e.g., might be PNG. Postfix doesn't matter, though.
|
181
|
+
trmt = Tempfile.new([localname + '_remote_', '.lua'])
|
182
|
+
tlcl = Tempfile.new([localname + '_local_', '.lua'])
|
183
|
+
[trmt, tlcl]
|
184
|
+
rescue StandardError => err
|
185
|
+
MrMurano::Verbose.error("Failed to create temporary file: #{err}")
|
186
|
+
raise
|
187
|
+
end
|
188
|
+
|
189
|
+
def dodiff_header_aware(merged, trmt, tlcl, options)
|
190
|
+
dodiff_download_remote(merged, trmt, options)
|
191
|
+
MrMurano::Verbose.whirly_stop
|
192
|
+
dodiff_prepare_local_and_diff(merged, trmt, tlcl, options)
|
193
|
+
ensure
|
194
|
+
trmt.close
|
195
|
+
trmt.unlink
|
196
|
+
tlcl.close
|
197
|
+
tlcl.unlink
|
198
|
+
end
|
199
|
+
|
200
|
+
def dodiff_download_remote(merged, trmt, options)
|
201
|
+
tmp_path = Pathname.new(trmt.path)
|
202
|
+
diff_download(tmp_path, merged, options)
|
203
|
+
end
|
204
|
+
|
205
|
+
def dodiff_prepare_local_and_diff(merged, trmt, tlcl, options)
|
206
|
+
cmd = dodiff_build_cmd(trmt, tlcl, options)
|
207
|
+
merged[:exclude_header] = true
|
208
|
+
outp = dodiff_flexible(merged, tlcl, local, cmd, use_header=false)
|
209
|
+
return outp if outp.to_s.empty? || !merged.key?(:script)
|
210
|
+
merged[:exclude_header] = false
|
211
|
+
dodiff_diff_dynamic(merged, tlcl, local, cmd, use_header=true)
|
212
|
+
end
|
213
|
+
|
214
|
+
def dodiff_build_cmd(trmt, tlcl, options)
|
215
|
+
# 2017-07-03: No worries, Ruby 3.0 frozen string literals, cmd is a list.
|
216
|
+
cmd = $cfg['diff.cmd'].shellsplit
|
217
|
+
# ALT_SEPARATOR is the platform specific alternative separator,
|
218
|
+
# for Windows support.
|
219
|
+
remote_path = trmt.path.gsub(
|
220
|
+
::File::SEPARATOR, ::File::ALT_SEPARATOR || ::File::SEPARATOR
|
221
|
+
)
|
222
|
+
local_path = tlcl.path.gsub(
|
223
|
+
::File::SEPARATOR, ::File::ALT_SEPARATOR || ::File::SEPARATOR
|
224
|
+
)
|
225
|
+
if options[:asdown]
|
226
|
+
cmd << local_path
|
227
|
+
cmd << remote_path
|
228
|
+
else
|
229
|
+
cmd << remote_path
|
230
|
+
cmd << local_path
|
178
231
|
end
|
232
|
+
cmd
|
233
|
+
end
|
234
|
+
|
235
|
+
def dodiff_flexible(merged, tlcl, local, cmd, use_header)
|
236
|
+
dodiff_local_to_tempfile(merged, tlcl, local, use_header)
|
237
|
+
dodiff_do_diff(cmd)
|
238
|
+
end
|
239
|
+
|
240
|
+
def dodiff_local_to_tempfile(merged, tlcl, local, use_header)
|
179
241
|
Pathname.new(tlcl.path).open('wb') do |io|
|
180
242
|
# Copy the local file to a temp file, for the diff command.
|
181
243
|
# And for resources, remove the local-only :selected key, as
|
182
244
|
# it's not part of the remote item that gets downloaded next.
|
183
245
|
if merged.key?(:script)
|
246
|
+
io << config_vars_decode(merged[:header]) if use_header
|
184
247
|
io << config_vars_decode(merged[:script])
|
185
248
|
else
|
186
249
|
# For most items, read the local file.
|
@@ -191,59 +254,34 @@ module MrMurano
|
|
191
254
|
diff_item_write(io, merged, local, nil)
|
192
255
|
end
|
193
256
|
end
|
257
|
+
end
|
194
258
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
MrMurano::Verbose.whirly_stop
|
259
|
+
def dodiff_do_diff(cmd)
|
260
|
+
stdout_and_stderr, _status = Open3.capture2e(*cmd)
|
261
|
+
dodiff_cull_tempfile_paths(stdout_and_stderr)
|
262
|
+
end
|
201
263
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
264
|
+
def dodiff_cull_tempfile_paths(stdout_and_stderr)
|
265
|
+
# How important are the first two lines of the diff? E.g.,
|
266
|
+
# --- /tmp/raw_data_remote_20170718-20183-gdyeg9.lua 2017-07-18 ...
|
267
|
+
# +++ /tmp/raw_data_local_20170718-20183-71o4me.lua 2017-07-18 ...
|
268
|
+
# Seems like printing the path to a since-deleted temporary file is
|
269
|
+
# misleading, so cull these lines.
|
270
|
+
unless $cfg['diff.cmd'] == 'diff' || $cfg['diff.cmd'].start_with?('diff ')
|
271
|
+
return stdout_and_stderr
|
272
|
+
end
|
273
|
+
lineno = 0
|
274
|
+
consise = stdout_and_stderr.lines.reject do |line|
|
275
|
+
lineno += 1
|
276
|
+
if lineno == 1 && line.start_with?('--- ')
|
277
|
+
true
|
278
|
+
elsif lineno == 2 && line.start_with?('+++ ')
|
279
|
+
true
|
215
280
|
else
|
216
|
-
|
217
|
-
cmd << local_path
|
218
|
-
end
|
219
|
-
|
220
|
-
stdout_and_stderr, _status = Open3.capture2e(*cmd)
|
221
|
-
# How important are the first two lines of the diff? E.g.,
|
222
|
-
# --- /tmp/raw_data_remote_20170718-20183-gdyeg9.lua 2017-07-18 ...
|
223
|
-
# +++ /tmp/raw_data_local_20170718-20183-71o4me.lua 2017-07-18 ...
|
224
|
-
# Seems like printing the path to a since-deleted temporary file is
|
225
|
-
# misleading, so cull these lines.
|
226
|
-
if $cfg['diff.cmd'] == 'diff' || $cfg['diff.cmd'].start_with?('diff ')
|
227
|
-
lineno = 0
|
228
|
-
consise = stdout_and_stderr.lines.reject do |line|
|
229
|
-
lineno += 1
|
230
|
-
if lineno == 1 && line.start_with?('--- ')
|
231
|
-
true
|
232
|
-
elsif lineno == 2 && line.start_with?('+++ ')
|
233
|
-
true
|
234
|
-
else
|
235
|
-
false
|
236
|
-
end
|
237
|
-
end
|
238
|
-
stdout_and_stderr = consise.join
|
281
|
+
false
|
239
282
|
end
|
240
|
-
ensure
|
241
|
-
trmt.close
|
242
|
-
trmt.unlink
|
243
|
-
tlcl.close
|
244
|
-
tlcl.unlink
|
245
283
|
end
|
246
|
-
|
284
|
+
consise.join
|
247
285
|
end
|
248
286
|
|
249
287
|
##
|
@@ -28,6 +28,8 @@ module MrMurano
|
|
28
28
|
attr_accessor :line_beg
|
29
29
|
# @return [Integer] The line in #local_path where this #script ends.
|
30
30
|
attr_accessor :line_end
|
31
|
+
# @return [String] The (optional) #ITEM <method> <path> :script header.
|
32
|
+
attr_accessor :header
|
31
33
|
# @return [String] If requested, the diff output.
|
32
34
|
attr_accessor :diff
|
33
35
|
# @return [Boolean] When filtering, did this item pass.
|
@@ -191,19 +191,20 @@ module MrMurano
|
|
191
191
|
# But on murano diff, MurCLI makes two local temp files
|
192
192
|
# to execute the diff, and it also upcases the method in
|
193
193
|
# both files, so the diff runs clean!
|
194
|
-
#
|
195
|
-
#
|
196
|
-
|
197
|
-
|
198
|
-
|
194
|
+
# 2017-07-03: (lb): Adding upcase; and recreating header.
|
195
|
+
# 2018-06-11: (lb): Added :exclude_header to deal with
|
196
|
+
# service side missing header. Which isn't an error, per se.
|
197
|
+
script_header = "--#ENDPOINT #{md[:method].upcase} #{md[:path]}"
|
198
|
+
script_header += " #{md[:ctype]}" unless md[:ctype].to_s.empty?
|
199
|
+
script_header += "\n"
|
199
200
|
cur = RouteItem.new(
|
200
|
-
#method: md[:method],
|
201
201
|
method: md[:method].upcase,
|
202
202
|
path: md[:path],
|
203
203
|
content_type: (md[:ctype] || 'application/json'),
|
204
204
|
local_path: path,
|
205
205
|
line_beg: lineno,
|
206
|
-
|
206
|
+
header: script_header,
|
207
|
+
script: '',
|
207
208
|
)
|
208
209
|
elsif !cur.nil? && !cur[:script].nil?
|
209
210
|
# 2017-07-02: Frozen string literal: change << to +=
|
@@ -99,6 +99,66 @@ command 'business list' do |c|
|
|
99
99
|
c.summary = %(List businesses)
|
100
100
|
c.description = %(
|
101
101
|
List businesses.
|
102
|
+
|
103
|
+
E.g.,
|
104
|
+
|
105
|
+
$ murano business find my
|
106
|
+
+-------------+-------+--------------------+
|
107
|
+
| bizid | role | name |
|
108
|
+
+-------------+-------+--------------------+
|
109
|
+
| a1b2c3d4e5f | owner | My Murano Business |
|
110
|
+
+-------------+-------+--------------------+
|
111
|
+
|
112
|
+
NOTE: To match businesses that use special characters in
|
113
|
+
their name, you must either delimit or quote the string.
|
114
|
+
|
115
|
+
For example, the Bash shell interprets the pound sign as
|
116
|
+
the start of a comment, so if you were to search, e.g.,
|
117
|
+
|
118
|
+
$ murano business find #
|
119
|
+
What would you like to find?
|
120
|
+
|
121
|
+
The CLI will not receive the '#' argument, and it'll tell
|
122
|
+
you as much.
|
123
|
+
|
124
|
+
The proper way to search for such a business is to either
|
125
|
+
delimit the query, or quote it. For example,
|
126
|
+
|
127
|
+
$ murano business find "#Hashtag Business"
|
128
|
+
+-------------+-------+-------------------+
|
129
|
+
| bizid | role | name |
|
130
|
+
+-------------+-------+-------------------+
|
131
|
+
| a1b2c3d4e5f | owner | #Hashtag Business |
|
132
|
+
+-------------+-------+-------------------+
|
133
|
+
|
134
|
+
The same applies for other special characters, such as:
|
135
|
+
|
136
|
+
'&' (start process in background);
|
137
|
+
'(' and ')' (subshell invocation);
|
138
|
+
'*' (file glob);
|
139
|
+
'~' (home directory expansion);
|
140
|
+
'!' (history expansion);
|
141
|
+
'-' (ignored as an empty option).
|
142
|
+
|
143
|
+
For example, to search for a name with a parenthesis, try:
|
144
|
+
|
145
|
+
$ murano business find \\\(
|
146
|
+
+-------------+-------+---------+
|
147
|
+
| bizid | role | name |
|
148
|
+
+-------------+-------+---------+
|
149
|
+
| a1b2c3d4e5f | owner | ( ͝° ͜ʖ͡°) |
|
150
|
+
+-------------+-------+---------+
|
151
|
+
|
152
|
+
Finally to search for a business name containing a dash,
|
153
|
+
use a double-dash to indicate the end of positional
|
154
|
+
arguments. For example,
|
155
|
+
|
156
|
+
$ murano business find -- -
|
157
|
+
+-------------+-------+----------------+
|
158
|
+
| bizid | role | name |
|
159
|
+
+-------------+-------+----------------+
|
160
|
+
| a1b2c3d4e5f | owner | Loch-Busi Ness |
|
161
|
+
+-------------+-------+----------------+
|
102
162
|
).strip
|
103
163
|
c.project_not_required = true
|
104
164
|
|
@@ -19,6 +19,7 @@ This is where OTA data can be stored so that devices can easily download it.
|
|
19
19
|
).strip
|
20
20
|
c.project_not_required = true
|
21
21
|
c.subcmdgrouphelp = true
|
22
|
+
c.must_not_be_managed = true
|
22
23
|
|
23
24
|
c.action do |_args, _options|
|
24
25
|
::Commander::UI.enable_paging unless $cfg['tool.no-page']
|
@@ -35,6 +36,7 @@ List downloadable content for a product.
|
|
35
36
|
Data uploaded to a product's content area can be downloaded by devices using
|
36
37
|
the HTTP Device API.
|
37
38
|
).strip
|
39
|
+
c.must_not_be_managed = true
|
38
40
|
|
39
41
|
c.option '-l', '--long', %(Include more info for each file)
|
40
42
|
|
@@ -50,7 +52,7 @@ the HTTP Device API.
|
|
50
52
|
if !items.empty?
|
51
53
|
prd.outf(items) do |dd, ios|
|
52
54
|
if options.long
|
53
|
-
headers = %i[Name Size
|
55
|
+
headers = %i[Name Size Last\ Modified MIME]
|
54
56
|
rows = dd.map { |d| [d[:id], d[:length], d[:last_modified], d[:type]] }
|
55
57
|
else
|
56
58
|
headers = %i[Name Size]
|
@@ -73,6 +75,7 @@ Show more info for a content item.
|
|
73
75
|
Data uploaded to a product's content area can be downloaded by devices using
|
74
76
|
the HTTP Device API.
|
75
77
|
).strip
|
78
|
+
c.must_not_be_managed = true
|
76
79
|
|
77
80
|
c.action do |args, _options|
|
78
81
|
c.verify_arg_count!(args, 1, ['Missing <content name>'])
|
@@ -93,6 +96,7 @@ Delete a content item.
|
|
93
96
|
Data uploaded to a product's content area can be downloaded by devices using
|
94
97
|
the HTTP Device API.
|
95
98
|
).strip
|
99
|
+
c.must_not_be_managed = true
|
96
100
|
|
97
101
|
c.option('-y', '--[no-]yes', %(Answer "yes" to all prompts and run non-interactively))
|
98
102
|
|
@@ -115,6 +119,7 @@ Upload a content item.
|
|
115
119
|
Data uploaded to a product's content area can be downloaded by devices using
|
116
120
|
the HTTP Device API.
|
117
121
|
).strip
|
122
|
+
c.must_not_be_managed = true
|
118
123
|
|
119
124
|
c.option('--tags KEY=VALUE', %(Add extra meta info to the content item)) do |ec|
|
120
125
|
key, value = ec.split('=', 2)
|
@@ -154,6 +159,7 @@ Download a content item.
|
|
154
159
|
Data uploaded to a product's content area can be downloaded by devices using
|
155
160
|
the HTTP Device API.
|
156
161
|
).strip
|
162
|
+
c.must_not_be_managed = true
|
157
163
|
|
158
164
|
c.option '-o', '--output FILE', %(Save content to a file)
|
159
165
|
|
@@ -284,7 +284,7 @@ end
|
|
284
284
|
|
285
285
|
command 'device activate' do |c|
|
286
286
|
c.syntax = %(murano device activate <identifier>)
|
287
|
-
c.summary = %(Activate a serial number,
|
287
|
+
c.summary = %(Activate a serial number, retrieving its CIK)
|
288
288
|
c.description = %(
|
289
289
|
Activate an Identifier.
|
290
290
|
|
@@ -30,9 +30,10 @@ class ElementCmd
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def reset_state
|
33
|
+
@drop_fields = []
|
33
34
|
@edit_fields = {}
|
35
|
+
@open_fields = []
|
34
36
|
@updated_obj = {}
|
35
|
-
@use_editor = false
|
36
37
|
@input_path = nil
|
37
38
|
@input_data = nil
|
38
39
|
end
|
@@ -325,7 +326,11 @@ class ElementCmd
|
|
325
326
|
cmd.option(
|
326
327
|
"--#{switch} [VALUE]", detail
|
327
328
|
) do |param|
|
328
|
-
|
329
|
+
if param.nil?
|
330
|
+
@open_fields.push(key)
|
331
|
+
else
|
332
|
+
@edit_fields[field.to_s] = param
|
333
|
+
end
|
329
334
|
end
|
330
335
|
end
|
331
336
|
end
|
@@ -336,11 +341,19 @@ class ElementCmd
|
|
336
341
|
) do |param|
|
337
342
|
if param.nil?
|
338
343
|
# param.nil? means user did not supply key[=val].
|
339
|
-
@
|
344
|
+
@open_fields.push('')
|
340
345
|
else
|
341
346
|
# Otherwise: a=b :> ['a', 'b'] / a= :> ['a', ''] / a :> ['a', nil]
|
342
347
|
key, value = param.split('=', 2)
|
343
|
-
|
348
|
+
if value.nil?
|
349
|
+
if param =~ /(?<!-)-$/
|
350
|
+
@drop_fields.push(key.chomp('-'))
|
351
|
+
else
|
352
|
+
@open_fields.push(key)
|
353
|
+
end
|
354
|
+
else
|
355
|
+
@edit_fields[key] = value
|
356
|
+
end
|
344
357
|
end
|
345
358
|
end
|
346
359
|
end
|
@@ -379,17 +392,16 @@ class ElementCmd
|
|
379
392
|
if @input_path.nil?
|
380
393
|
# See if all values are specified, or if we should bring up the EDITOR.
|
381
394
|
if n_kvals[:n_keys] > 1
|
382
|
-
if n_kvals[:n_keys]
|
395
|
+
if (n_kvals[:n_keys] + 1) < n_kvals[:n_vals]
|
396
|
+
# EDITOR path, i.e., one key specified without a value.
|
383
397
|
error %(
|
384
|
-
Please specify at most one field
|
398
|
+
Please specify at most one field without a value.
|
385
399
|
).strip
|
386
400
|
exit 2
|
387
401
|
end
|
388
|
-
elsif n_kvals[:n_keys] == 0
|
402
|
+
elsif n_kvals[:n_keys] == 0 && @open_fields.empty?
|
389
403
|
error('Please specify one or more -e/--edit options, or an input file.')
|
390
404
|
exit 2
|
391
|
-
else
|
392
|
-
@use_editor = n_kvals[:n_vals].zero?
|
393
405
|
end
|
394
406
|
elsif n_kvals[:n_keys] > 1
|
395
407
|
error('Please specify at most a single field when specifing an input file.')
|
@@ -423,13 +435,17 @@ class ElementCmd
|
|
423
435
|
n_edits = 0
|
424
436
|
# When @edit_fields == { '' => '' }, BizAPI replies:
|
425
437
|
# Request Failed: 400: [400] child "type" fails because ["type" is required]
|
426
|
-
if
|
438
|
+
if !@open_fields.empty?
|
439
|
+
if (@open_fields.length > 1) && $cfg['tool.developer']
|
440
|
+
warning %(Unexpected: more than one open field specified)
|
441
|
+
end
|
427
442
|
n_edits += update_elem_fields_from_editor
|
428
443
|
else
|
429
444
|
# Verify that at least one option value differs from what's currently set.
|
430
445
|
n_edits += update_elem_fields_from_options
|
431
446
|
n_edits += update_elem_fields_from_input_f
|
432
447
|
end
|
448
|
+
n_edits += update_elem_fields_drop_fields
|
433
449
|
if n_edits.zero?
|
434
450
|
warning('No new field values specified to update.')
|
435
451
|
exit 0
|
@@ -447,7 +463,7 @@ class ElementCmd
|
|
447
463
|
end
|
448
464
|
|
449
465
|
def prepare_field_keys_and_value
|
450
|
-
field = @
|
466
|
+
field = @open_fields[0]
|
451
467
|
keys = []
|
452
468
|
keys = field.split('.').map(&:to_sym) unless field.to_s.empty?
|
453
469
|
if !keys.nil? && !keys.empty?
|
@@ -535,10 +551,10 @@ class ElementCmd
|
|
535
551
|
def update_elem_fields_from_input_f
|
536
552
|
n_edits = 0
|
537
553
|
return n_edits if @input_path.nil?
|
538
|
-
if (@
|
539
|
-
warning %(Unexpected: more than one field specified)
|
554
|
+
if (@open_fields.length > 1) && $cfg['tool.developer']
|
555
|
+
warning %(Unexpected: more than one open field specified)
|
540
556
|
end
|
541
|
-
keys = @
|
557
|
+
keys = @open_fields[0].split('.').map(&:to_sym) unless @open_fields.empty?
|
542
558
|
if !keys.nil? && !keys.empty?
|
543
559
|
old_val = @updated_obj.dig_safe(*keys)
|
544
560
|
if old_val != @input_data
|
@@ -552,6 +568,16 @@ class ElementCmd
|
|
552
568
|
n_edits
|
553
569
|
end
|
554
570
|
|
571
|
+
def update_elem_fields_drop_fields
|
572
|
+
n_edits = 0
|
573
|
+
@drop_fields.each do |field|
|
574
|
+
keys = field.split('.').map(&:to_sym)
|
575
|
+
@updated_obj.deep_delete(*keys)
|
576
|
+
n_edits += 1
|
577
|
+
end
|
578
|
+
n_edits
|
579
|
+
end
|
580
|
+
|
555
581
|
def value_specifies_file_input?(field_value)
|
556
582
|
field_value =~ /^@(?!@)/
|
557
583
|
end
|
@@ -32,6 +32,7 @@ command 'keystore clearAll' do |c|
|
|
32
32
|
c.description = %(
|
33
33
|
Delete all keys in the keystore.
|
34
34
|
).strip
|
35
|
+
c.must_not_be_managed = true
|
35
36
|
|
36
37
|
c.action do |args, _options|
|
37
38
|
c.verify_arg_count!(args)
|
@@ -46,6 +47,7 @@ command 'keystore info' do |c|
|
|
46
47
|
c.description = %(
|
47
48
|
Show info about the Keystore.
|
48
49
|
).strip
|
50
|
+
c.must_not_be_managed = true
|
49
51
|
|
50
52
|
c.action do |args, _options|
|
51
53
|
c.verify_arg_count!(args)
|
@@ -60,6 +62,7 @@ command 'keystore list' do |c|
|
|
60
62
|
c.description = %(
|
61
63
|
List all of the keys in the Keystore.
|
62
64
|
).strip
|
65
|
+
c.must_not_be_managed = true
|
63
66
|
|
64
67
|
c.action do |args, _options|
|
65
68
|
c.verify_arg_count!(args)
|
@@ -76,6 +79,7 @@ command 'keystore get' do |c|
|
|
76
79
|
c.description = %(
|
77
80
|
Get the value of a key in the Keystore.
|
78
81
|
).strip
|
82
|
+
c.must_not_be_managed = true
|
79
83
|
|
80
84
|
c.action do |args, _options|
|
81
85
|
c.verify_arg_count!(args, 1, ['Missing key'])
|
@@ -91,6 +95,7 @@ command 'keystore set' do |c|
|
|
91
95
|
c.description = %(
|
92
96
|
Set the value of a key in the Keystore.
|
93
97
|
).strip
|
98
|
+
c.must_not_be_managed = true
|
94
99
|
|
95
100
|
c.action do |args, _options|
|
96
101
|
c.verify_arg_count!(args, nil, ['Missing key', 'Missing value(s)'])
|
@@ -105,6 +110,7 @@ command 'keystore delete' do |c|
|
|
105
110
|
c.description = %(
|
106
111
|
Delete a key from the Keystore.
|
107
112
|
).strip
|
113
|
+
c.must_not_be_managed = true
|
108
114
|
|
109
115
|
# MAYBE?/2017-08-16: Verify on delete.
|
110
116
|
#c.option('-y', '--[no-]yes', %(Answer "yes" to all prompts and run non-interactively))
|
@@ -130,6 +136,8 @@ For current list, see:
|
|
130
136
|
|
131
137
|
http://docs.exosite.com/murano/services/keystore/#command
|
132
138
|
).strip
|
139
|
+
c.must_not_be_managed = true
|
140
|
+
|
133
141
|
c.example %(murano keystore command lpush mykey myvalue), %(Push a value onto list)
|
134
142
|
c.example %(murano keystore command lpush mykey A B C), %(Push three values onto list)
|
135
143
|
c.example %(murano keystore command lrem mykey 0 B), %(Remove all B values from list)
|