MuranoCLI 3.2.0.beta.1 → 3.2.0.beta.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +4 -1
- data/.trustme.plugin +137 -0
- data/.trustme.sh +217 -117
- data/.trustme.vim +9 -3
- data/Gemfile +9 -3
- data/MuranoCLI.gemspec +8 -5
- data/Rakefile +1 -0
- data/dockers/Dockerfile.2.2.9 +6 -3
- data/dockers/Dockerfile.2.3.6 +6 -3
- data/dockers/Dockerfile.2.4.3 +6 -3
- data/dockers/Dockerfile.2.5.0 +6 -3
- data/dockers/Dockerfile.GemRelease +10 -8
- data/dockers/Dockerfile.m4 +23 -5
- data/dockers/docker-test.sh +65 -28
- data/docs/completions/murano_completion-bash +751 -57
- data/docs/develop.rst +10 -9
- data/lib/MrMurano/AccountBase.rb +95 -6
- data/lib/MrMurano/Commander-Entry.rb +9 -4
- data/lib/MrMurano/Config-Migrate.rb +2 -0
- data/lib/MrMurano/Config.rb +94 -26
- data/lib/MrMurano/Content.rb +1 -1
- data/lib/MrMurano/Exchange.rb +77 -42
- data/lib/MrMurano/Gateway.rb +1 -1
- data/lib/MrMurano/HttpAuthed.rb +20 -7
- data/lib/MrMurano/Logs.rb +10 -1
- data/lib/MrMurano/ProjectFile.rb +1 -1
- data/lib/MrMurano/ReCommander.rb +129 -73
- data/lib/MrMurano/Solution-ServiceConfig.rb +18 -11
- data/lib/MrMurano/Solution-Services.rb +78 -50
- data/lib/MrMurano/Solution-Users.rb +1 -1
- data/lib/MrMurano/Solution.rb +13 -63
- data/lib/MrMurano/SyncUpDown-Core.rb +185 -77
- data/lib/MrMurano/SyncUpDown-Item.rb +29 -4
- data/lib/MrMurano/SyncUpDown.rb +11 -11
- data/lib/MrMurano/Webservice-Cors.rb +1 -1
- data/lib/MrMurano/Webservice-Endpoint.rb +28 -17
- data/lib/MrMurano/Webservice-File.rb +103 -43
- data/lib/MrMurano/commands/domain.rb +1 -0
- data/lib/MrMurano/commands/element.rb +585 -0
- data/lib/MrMurano/commands/exchange.rb +211 -204
- data/lib/MrMurano/commands/gb.rb +1 -0
- data/lib/MrMurano/commands/globals.rb +17 -7
- data/lib/MrMurano/commands/init.rb +115 -101
- data/lib/MrMurano/commands/keystore.rb +1 -1
- data/lib/MrMurano/commands/logs.rb +2 -1
- data/lib/MrMurano/commands/postgresql.rb +17 -7
- data/lib/MrMurano/commands/service.rb +572 -0
- data/lib/MrMurano/commands/show.rb +7 -3
- data/lib/MrMurano/commands/solution.rb +2 -1
- data/lib/MrMurano/commands/solution_picker.rb +31 -15
- data/lib/MrMurano/commands/status.rb +205 -169
- data/lib/MrMurano/commands/sync.rb +70 -38
- data/lib/MrMurano/commands/token.rb +59 -14
- data/lib/MrMurano/commands/usage.rb +1 -0
- data/lib/MrMurano/commands.rb +2 -0
- data/lib/MrMurano/hash.rb +91 -0
- data/lib/MrMurano/http.rb +55 -6
- data/lib/MrMurano/makePretty.rb +47 -0
- data/lib/MrMurano/optparse.rb +60 -45
- data/lib/MrMurano/variegated/TruthyFalsey.rb +48 -0
- data/lib/MrMurano/variegated/ruby_dig.rb +64 -0
- data/lib/MrMurano/verbosing.rb +113 -3
- data/lib/MrMurano/version.rb +1 -1
- data/spec/Account_spec.rb +34 -20
- data/spec/Business_spec.rb +12 -9
- data/spec/Config_spec.rb +7 -1
- data/spec/Content_spec.rb +17 -1
- data/spec/GatewayBase_spec.rb +5 -2
- data/spec/GatewayDevice_spec.rb +4 -2
- data/spec/GatewayResource_spec.rb +4 -1
- data/spec/GatewaySettings_spec.rb +4 -1
- data/spec/HttpAuthed_spec.rb +73 -0
- data/spec/Http_spec.rb +32 -35
- data/spec/ProjectFile_spec.rb +1 -1
- data/spec/Solution-ServiceConfig_spec.rb +4 -1
- data/spec/Solution-ServiceEventHandler_spec.rb +6 -3
- data/spec/Solution-ServiceModules_spec.rb +4 -1
- data/spec/Solution-UsersRoles_spec.rb +4 -1
- data/spec/Solution_spec.rb +4 -1
- data/spec/SyncUpDown_spec.rb +1 -1
- data/spec/Webservice-Cors_spec.rb +4 -1
- data/spec/Webservice-Endpoint_spec.rb +9 -6
- data/spec/Webservice-File_spec.rb +17 -4
- data/spec/Webservice-Setting_spec.rb +6 -2
- data/spec/_workspace.rb +2 -0
- data/spec/cmd_common.rb +42 -13
- data/spec/cmd_content_spec.rb +17 -7
- data/spec/cmd_device_spec.rb +1 -1
- data/spec/cmd_domain_spec.rb +2 -2
- data/spec/cmd_element_spec.rb +400 -0
- data/spec/cmd_exchange_spec.rb +2 -2
- data/spec/cmd_init_spec.rb +59 -25
- data/spec/cmd_keystore_spec.rb +6 -3
- data/spec/cmd_link_spec.rb +10 -5
- data/spec/cmd_logs_spec.rb +1 -1
- data/spec/cmd_setting_application_spec.rb +18 -15
- data/spec/cmd_setting_product_spec.rb +7 -7
- data/spec/cmd_status_spec.rb +27 -17
- data/spec/cmd_syncdown_application_spec.rb +30 -3
- data/spec/cmd_syncdown_both_spec.rb +72 -18
- data/spec/cmd_syncup_spec.rb +71 -5
- data/spec/cmd_token_spec.rb +2 -2
- data/spec/cmd_usage_spec.rb +2 -2
- data/spec/dry_run_formatter.rb +27 -0
- data/spec/fixtures/dumped_config +8 -0
- data/spec/fixtures/exchange_element/element-show.json +1 -0
- data/spec/fixtures/exchange_element/swagger-mur-6407__10k.yaml +282 -0
- data/spec/fixtures/exchange_element/swagger-mur-6407__20k.yaml +588 -0
- data/spec/variegated_TruthyFalsey_spec.rb +29 -0
- metadata +51 -25
data/lib/MrMurano/Exchange.rb
CHANGED
@@ -6,6 +6,7 @@
|
|
6
6
|
# Unauthorized copying of this file is strictly prohibited.
|
7
7
|
|
8
8
|
require 'MrMurano/AccountBase'
|
9
|
+
require 'MrMurano/Business'
|
9
10
|
require 'MrMurano/Exchange-Element'
|
10
11
|
require 'MrMurano/verbosing'
|
11
12
|
|
@@ -19,56 +20,47 @@ module MrMurano
|
|
19
20
|
super
|
20
21
|
end
|
21
22
|
|
23
|
+
def put(element_id, body={}, &block)
|
24
|
+
super('exchange/' + bid + '/element/' + element_id, body, &block)
|
25
|
+
end
|
26
|
+
|
22
27
|
def element(element_id)
|
28
|
+
element_by_id(element_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
def element_by_id(element_id)
|
23
32
|
ret = get('exchange/' + bid + '/element/' + element_id)
|
24
33
|
return nil unless ret.is_a?(Hash) && !ret.key?(:error)
|
25
34
|
ret
|
26
35
|
end
|
27
36
|
|
28
|
-
def
|
29
|
-
#
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
when '/purchase/'
|
35
|
-
qualifier = 'Purchased'
|
36
|
-
else
|
37
|
-
raise 'Unexpected error'
|
38
|
-
end
|
39
|
-
whirly_start("Fetching #{qualifier} Elements...")
|
37
|
+
def element_quick(element_id)
|
38
|
+
# Check if ID, a 24-character hexadecimal string.
|
39
|
+
smells_like_id = element_id =~ /^[\h]{24}$/
|
40
|
+
return element_by_id(element_id) if smells_like_id
|
41
|
+
nil
|
42
|
+
end
|
40
43
|
|
41
|
-
|
42
|
-
#
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
showHttpError(request, response)
|
51
|
-
end
|
52
|
-
end
|
53
|
-
whirly_stop
|
54
|
-
return [] unless ret.is_a?(Hash) && !ret.key?(:error)
|
55
|
-
return [] unless ret.key?(:items)
|
56
|
-
unless ret[:count] == ret[:items].length
|
57
|
-
warning(
|
58
|
-
'Unexpected: ret[:count] != ret[:items].length: ' \
|
59
|
-
"#{ret[:count]} != #{ret[:items].length}"
|
60
|
-
)
|
44
|
+
def elements(skip_purchased: false, **opts)
|
45
|
+
# Get the user's Business metadata, including their Business tier.
|
46
|
+
overview if @ometa.nil?
|
47
|
+
|
48
|
+
elems = nil
|
49
|
+
id_maybe = opts[:filter_id] || opts[:filter_fuzzy]
|
50
|
+
if id_maybe && skip_purchased
|
51
|
+
elem = element_quick(id_maybe)
|
52
|
+
elems = [MrMurano::ExchangeElement.new(elem)] unless elem.nil?
|
61
53
|
end
|
62
|
-
|
54
|
+
elems = elements_all(skip_purchased: skip_purchased) if elems.nil?
|
55
|
+
|
56
|
+
prepare_elements(elems, **opts)
|
63
57
|
end
|
64
58
|
|
65
|
-
def
|
59
|
+
def elements_all(skip_purchased: false)
|
66
60
|
lookp = {}
|
67
|
-
# Get the user's Business metadata, including their Business tier.
|
68
|
-
overview if @ometa.nil?
|
69
61
|
elems = fetch_elements(lookp)
|
70
|
-
fetch_purchased(lookp)
|
71
|
-
|
62
|
+
fetch_purchased(lookp) unless skip_purchased
|
63
|
+
elems
|
72
64
|
end
|
73
65
|
|
74
66
|
def fetch_elements(lookp)
|
@@ -82,9 +74,11 @@ module MrMurano
|
|
82
74
|
end
|
83
75
|
end
|
84
76
|
|
85
|
-
def fetch_purchased(lookp)
|
77
|
+
def fetch_purchased(lookp=nil, services_only: false)
|
78
|
+
query = [%w[type service]] if services_only
|
86
79
|
# Fetch the list of Purchased elements.
|
87
|
-
items = fetch_type('/purchase/')
|
80
|
+
items = fetch_type('/purchase/', query)
|
81
|
+
return items if lookp.nil?
|
88
82
|
# Update the list of all Elements to indicate which have been purchased.
|
89
83
|
items.each do |meta|
|
90
84
|
elem = lookp[meta[:elementId]]
|
@@ -99,15 +93,56 @@ module MrMurano
|
|
99
93
|
)
|
100
94
|
end
|
101
95
|
else
|
102
|
-
warning(
|
96
|
+
warning(
|
97
|
+
"No Exchange Element for Purchase: elementId: #{meta[:elementId]}"
|
98
|
+
)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def fetch_type(part, query=nil)
|
104
|
+
# [lb] not super happy about mixing presentation with other logic
|
105
|
+
# but this is quick and dirty.
|
106
|
+
case part
|
107
|
+
when '/element/'
|
108
|
+
qualifier = 'All'
|
109
|
+
when '/purchase/'
|
110
|
+
qualifier = 'Purchased'
|
111
|
+
else
|
112
|
+
raise 'Unexpected error'
|
113
|
+
end
|
114
|
+
whirly_start("Fetching #{qualifier} Elements...")
|
115
|
+
|
116
|
+
# FIXME/2017-09-27: Support Pagination. BizAPI accepts four settings:
|
117
|
+
# type, offset, limit, and select.
|
118
|
+
# <bizapi>/lib/api/route/exchange/schemas/element.js
|
119
|
+
ret = get('exchange/' + bid + part, query) do |request, http|
|
120
|
+
response = http.request(request)
|
121
|
+
case response
|
122
|
+
when Net::HTTPSuccess
|
123
|
+
workit_response(response)
|
124
|
+
else
|
125
|
+
showHttpError(request, response)
|
103
126
|
end
|
104
127
|
end
|
128
|
+
whirly_stop
|
129
|
+
return [] unless ret.is_a?(Hash) && !ret.key?(:error)
|
130
|
+
return [] unless ret.key?(:items)
|
131
|
+
unless ret[:count] == ret[:items].length
|
132
|
+
warning(
|
133
|
+
'Unexpected: ret[:count] != ret[:items].length: ' \
|
134
|
+
"#{ret[:count]} != #{ret[:items].length}"
|
135
|
+
)
|
136
|
+
end
|
137
|
+
ret[:items]
|
105
138
|
end
|
106
139
|
|
107
140
|
def verify_purchase_vs_element(elem, key, val)
|
108
141
|
elem.send(key) == val
|
109
142
|
rescue NoMethodError
|
110
|
-
verbose(
|
143
|
+
verbose(
|
144
|
+
"Unexpected: Exchange Element missing key found in Purchase Element: #{key}"
|
145
|
+
)
|
111
146
|
true
|
112
147
|
end
|
113
148
|
|
data/lib/MrMurano/Gateway.rb
CHANGED
data/lib/MrMurano/HttpAuthed.rb
CHANGED
@@ -22,14 +22,12 @@ module MrMurano
|
|
22
22
|
include Http
|
23
23
|
include Verbose
|
24
24
|
|
25
|
+
attr_accessor :logging_on
|
25
26
|
attr_accessor :login_info
|
26
27
|
attr_reader :token_biz
|
27
28
|
|
28
29
|
def initialize
|
29
|
-
|
30
|
-
@pass_file = nil
|
31
|
-
@token_file = nil
|
32
|
-
token_reset
|
30
|
+
credentials_reset
|
33
31
|
end
|
34
32
|
|
35
33
|
def add_headers(request)
|
@@ -52,6 +50,15 @@ module MrMurano
|
|
52
50
|
request
|
53
51
|
end
|
54
52
|
|
53
|
+
def credentials_reset
|
54
|
+
@logging_on = false
|
55
|
+
@login_info = nil
|
56
|
+
@pass_file = nil
|
57
|
+
@token_file = nil
|
58
|
+
token_reset
|
59
|
+
@password_user = ''
|
60
|
+
end
|
61
|
+
|
55
62
|
# ---------------------------------------------------------------------
|
56
63
|
|
57
64
|
def pass_file
|
@@ -118,8 +125,10 @@ module MrMurano
|
|
118
125
|
@token_biz
|
119
126
|
end
|
120
127
|
|
121
|
-
def token_reset
|
122
|
-
|
128
|
+
def token_reset(new_token='')
|
129
|
+
# Setting the empty token will cause it to be re-fetched
|
130
|
+
# on next login_info.
|
131
|
+
@token_biz = new_token
|
123
132
|
end
|
124
133
|
|
125
134
|
def ensure_token!
|
@@ -140,7 +149,7 @@ module MrMurano
|
|
140
149
|
acc_token = token_file.lookup(net_host, user_name)
|
141
150
|
if acc_token.to_s.empty?
|
142
151
|
nil
|
143
|
-
elsif acc_token
|
152
|
+
elsif !token_looks_legit(acc_token)
|
144
153
|
warning "Malformed '#{net_host}:#{user_name}' token: #{acc_token}"
|
145
154
|
nil
|
146
155
|
else
|
@@ -148,6 +157,10 @@ module MrMurano
|
|
148
157
|
end
|
149
158
|
end
|
150
159
|
|
160
|
+
def token_looks_legit(acc_token)
|
161
|
+
(acc_token =~ /^[a-fA-F0-9]{40}$/) == 0
|
162
|
+
end
|
163
|
+
|
151
164
|
def token_save(net_host=nil, user_name=nil)
|
152
165
|
net_host, user_name = get_host_user_pair(net_host, user_name)
|
153
166
|
return unless $cfg['auth.persist-token']
|
data/lib/MrMurano/Logs.rb
CHANGED
@@ -5,7 +5,16 @@
|
|
5
5
|
# vim:tw=0:ts=2:sw=2:et:ai
|
6
6
|
# Unauthorized copying of this file is strictly prohibited.
|
7
7
|
|
8
|
-
|
8
|
+
begin
|
9
|
+
require 'eventmachine'
|
10
|
+
rescue StandardError => _err
|
11
|
+
# (lb): I started developing in tmux, and I get this error only within it:
|
12
|
+
# require 'eventmachine'
|
13
|
+
# Unable to load the EventMachine C extension;
|
14
|
+
# To use the pure-ruby reactor, require 'em/pure_ruby'
|
15
|
+
require 'em/pure_ruby'
|
16
|
+
end
|
17
|
+
|
9
18
|
require 'faye/websocket'
|
10
19
|
|
11
20
|
require 'MrMurano/http'
|
data/lib/MrMurano/ProjectFile.rb
CHANGED
@@ -8,9 +8,9 @@
|
|
8
8
|
# 2017-07-01: This ordered list hacks around having
|
9
9
|
# individual files include all the files they need.
|
10
10
|
|
11
|
-
require 'yaml'
|
12
11
|
require 'json-schema'
|
13
12
|
require 'pathname'
|
13
|
+
require 'yaml'
|
14
14
|
require 'MrMurano/verbosing'
|
15
15
|
require 'MrMurano/Config'
|
16
16
|
require 'MrMurano/hash'
|
data/lib/MrMurano/ReCommander.rb
CHANGED
@@ -127,12 +127,29 @@ module Commander
|
|
127
127
|
hooked.check_run_post_hook
|
128
128
|
end
|
129
129
|
|
130
|
+
alias old_args_without_command_name args_without_command_name
|
131
|
+
def args_without_command_name
|
132
|
+
args_sans = old_args_without_command_name
|
133
|
+
args_sans += ['--'] + @positional unless @positional.empty?
|
134
|
+
args_sans
|
135
|
+
end
|
136
|
+
|
137
|
+
alias old_remove_global_options remove_global_options
|
138
|
+
def remove_global_options(options, args)
|
139
|
+
# Look for sole '--' argument, which signals start of positionals.
|
140
|
+
i_positional = args.index('--')
|
141
|
+
args = args[0, i_positional] unless i_positional.nil?
|
142
|
+
old_remove_global_options(options, args)
|
143
|
+
end
|
144
|
+
|
130
145
|
alias old_parse_global_options parse_global_options
|
131
146
|
def parse_global_options
|
132
147
|
# User can specify, e.g., status.options, to set options for specific commands.
|
133
148
|
defopts = ($cfg["#{active_command.name}.options"] || '').split
|
134
149
|
@args.push(*defopts)
|
135
|
-
|
150
|
+
end_of_options_hack
|
151
|
+
do_help = help_hack
|
152
|
+
$cfg.validate_cmd_business_and_project(active_command) unless do_help
|
136
153
|
parse_global_options_real
|
137
154
|
end
|
138
155
|
|
@@ -150,12 +167,21 @@ module Commander
|
|
150
167
|
exit 2
|
151
168
|
end
|
152
169
|
|
170
|
+
def end_of_options_hack
|
171
|
+
@positional = []
|
172
|
+
i_positional = @args.index('--')
|
173
|
+
return if i_positional.nil?
|
174
|
+
@positional = @args[i_positional + 1..-1]
|
175
|
+
@args = @args[0, i_positional]
|
176
|
+
end
|
177
|
+
|
153
178
|
# 2017-08-22: Commander's help infrastructure is either really weak,
|
154
179
|
# or we did something elsewhere that seriously cripples it. In any
|
155
180
|
# case, this fixes all its quirks.
|
156
181
|
def help_hack
|
157
|
-
do_help =
|
182
|
+
do_help = fix_args_for_help
|
158
183
|
show_alias_help_maybe! if do_help
|
184
|
+
do_help
|
159
185
|
end
|
160
186
|
|
161
187
|
def help_opts
|
@@ -166,7 +192,7 @@ module Commander
|
|
166
192
|
%w[-v --version].freeze
|
167
193
|
end
|
168
194
|
|
169
|
-
def
|
195
|
+
def fix_args_for_help
|
170
196
|
# If `murano --help` is specified, let rb-commander handle it.
|
171
197
|
# But if `murano command --help` is specified, don't let cmdr
|
172
198
|
# handle it, otherwise it just shows the command description,
|
@@ -175,79 +201,110 @@ module Commander
|
|
175
201
|
# 'help' might really be a command argument (e.g., a solution name).
|
176
202
|
# Note: `murano -v`'s active_command is 'help'.
|
177
203
|
do_help = (@args & %w[-h --help]).any? || active_command.name == 'help'
|
178
|
-
if do_help
|
179
|
-
# If there are options in addition to --help, then Commander
|
180
|
-
# runs the command! So remove all options.
|
181
|
-
#
|
182
|
-
# E.g., this shows the help for usage:
|
183
|
-
# $ murano --help usage
|
184
|
-
# but if a flag is added, the command gets run, e.g.,
|
185
|
-
# $ murano usage --id 1234 --help
|
186
|
-
# runs the usage command.
|
187
|
-
#
|
188
|
-
# I [lb] walked the code and it looks like when Commander tries to
|
189
|
-
# validate the args, it doesn't like the --id flag (maybe because
|
190
|
-
# the "help" command is being used to validate, and it does not
|
191
|
-
# define any options?). Then it removes the --id switch (after the
|
192
|
-
# --help switch was previously removed) and tries the command *again*
|
193
|
-
# (in gems/commander-4.4.3/lib/commander/runner.rb, look for the
|
194
|
-
# comment, "Remove the offending args and retry"). So in the example
|
195
|
-
# given above, `murano usage --id 1234 --help`, both the `--id` flag
|
196
|
-
# and `--help` flag are moved from @args, and then `murano usage 1234`
|
197
|
-
# is executed (and args are not validated by Commander but merely passed
|
198
|
-
# to the command action, so `usage` gets args=['1234']). Whadda wreck.
|
199
|
-
reject_next = false
|
200
|
-
@args.reject! do |arg|
|
201
|
-
reject = false
|
202
|
-
if reject_next
|
203
|
-
reject = true
|
204
|
-
reject_next = false
|
205
|
-
elsif arg.start_with?('-') && !help_opts.include?(arg) && !vers_opts.include?(arg)
|
206
|
-
reject = true
|
207
|
-
# See if the next argument should also be consumed.
|
208
|
-
arg_opts = @options.select do |opt|
|
209
|
-
if arg =~ /^-[^-]/
|
210
|
-
# Single char abbrev: look for exact match.
|
211
|
-
opt[:switches].include?(arg)
|
212
|
-
else
|
213
|
-
# Long switch: Commander matches abbrevs of longs...
|
214
|
-
opt[:switches].any? { |oarg| oarg =~ /^#{arg}/ }
|
215
|
-
end
|
216
|
-
end
|
217
|
-
if arg =~ /^--/
|
218
|
-
exact = arg_opts.select do |opt|
|
219
|
-
opt[:switches].include?(arg) || opt[:switches].any? do |sw|
|
220
|
-
sw.start_with?(arg + ' ')
|
221
|
-
end
|
222
|
-
end
|
223
|
-
arg_opts = exact unless exact.empty?
|
224
|
-
end
|
225
|
-
if arg_opts.length > 1
|
226
|
-
# MAYBE/2017-08-23: Always do this check, not just for help.
|
227
|
-
ambig = MrMurano::Verbose.fancy_ticks(arg)
|
228
|
-
match = arg_opts.map do |opt|
|
229
|
-
opt[:switches].map { |sw| MrMurano::Verbose.fancy_ticks(sw) }.join('|')
|
230
|
-
end
|
231
|
-
match = match.flatten
|
232
|
-
match[-1] = "and #{match[-1]}" if match.length > 1
|
233
|
-
match = match.join(', ')
|
234
|
-
MrMurano::Verbose.error("Ambiguous option: #{ambig} matches: #{match}")
|
235
|
-
exit 2
|
236
|
-
elsif arg_opts.length == 1
|
237
|
-
if arg_opts.first[:switches].any? { |opt| opt.start_with?('--') && opt.include?(' ') }
|
238
|
-
# There's a space in the --long setting, e.g., '--config KEY=VAL',
|
239
|
-
# so we know there's an argument following.
|
240
|
-
reject_next = true
|
241
|
-
end
|
242
|
-
end
|
243
|
-
end
|
244
|
-
reject
|
245
|
-
end
|
246
|
-
end
|
204
|
+
trim_options_from_args if do_help
|
247
205
|
@purargs = @args - help_opts
|
248
206
|
return do_help if active_command.name == 'help'
|
249
207
|
# Any command other than `murano help` or `murano --help`.
|
250
208
|
return do_help if !do_help || active_command.name.include?(' ')
|
209
|
+
# Command is not --help, or it's help for a single-word command.
|
210
|
+
cleanup_args_simple_command_help
|
211
|
+
do_help
|
212
|
+
end
|
213
|
+
|
214
|
+
# If there are options in addition to --help, then Commander
|
215
|
+
# runs the command! So remove all options.
|
216
|
+
#
|
217
|
+
# E.g., this shows the help for usage:
|
218
|
+
#
|
219
|
+
# $ murano --help usage
|
220
|
+
#
|
221
|
+
# but if a flag is added, the command gets run, e.g.,
|
222
|
+
#
|
223
|
+
# $ murano usage --id 1234 --help
|
224
|
+
#
|
225
|
+
# runs the usage command.
|
226
|
+
#
|
227
|
+
# (lb): I walked the code and it looks like when Commander tries to
|
228
|
+
# validate the args, it doesn't like the --id flag (maybe because
|
229
|
+
# the "help" command is being used to validate, and it does not
|
230
|
+
# define any options?). Then it removes the --id switch (after the
|
231
|
+
# --help switch was previously removed) and tries the command *again*
|
232
|
+
# (in gems/commander-4.4.3/lib/commander/runner.rb, look for the
|
233
|
+
# comment, "Remove the offending args and retry"). So in the example
|
234
|
+
# given above, `murano usage --id 1234 --help`, both the `--id` flag
|
235
|
+
# and `--help` flag are moved from @args, and then `murano usage 1234`
|
236
|
+
# is executed (and args are not validated by Commander but merely passed
|
237
|
+
# to the command action, so `usage` gets args=['1234']). Whadda wreck.
|
238
|
+
def trim_options_from_args
|
239
|
+
reject_next = false
|
240
|
+
@args.reject! do |arg|
|
241
|
+
if reject_next
|
242
|
+
reject_next = false
|
243
|
+
true
|
244
|
+
elsif (
|
245
|
+
arg.start_with?('-') &&
|
246
|
+
!help_opts.include?(arg) &&
|
247
|
+
!vers_opts.include?(arg)
|
248
|
+
)
|
249
|
+
# See if the next argument should also be consumed.
|
250
|
+
arg_opts = find_matching_options(arg)
|
251
|
+
arg_opts = find_exact_match_maybe(arg, arg_opts)
|
252
|
+
reject_next = must_be_sane_option!(arg_opts)
|
253
|
+
true
|
254
|
+
else
|
255
|
+
false
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
def find_matching_options(arg)
|
261
|
+
@options.select do |opt|
|
262
|
+
if arg =~ /^-[^-]/
|
263
|
+
# Single char abbrev: look for exact match.
|
264
|
+
opt[:switches].include?(arg)
|
265
|
+
else
|
266
|
+
# Long switch: Commander matches abbrevs of longs...
|
267
|
+
opt[:switches].any? { |oarg| oarg =~ /^#{arg}/ }
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def find_exact_match_maybe(arg, arg_opts)
|
273
|
+
return arg_opts unless arg =~ /^--/
|
274
|
+
exact = arg_opts.select do |opt|
|
275
|
+
opt[:switches].include?(arg) || opt[:switches].any? do |sw|
|
276
|
+
sw.start_with?(arg + ' ')
|
277
|
+
end
|
278
|
+
end
|
279
|
+
exact.empty? && exact || arg_opts
|
280
|
+
end
|
281
|
+
|
282
|
+
# Returns true if next arg is input to current --option.
|
283
|
+
def must_be_sane_option!(arg_opts)
|
284
|
+
if arg_opts.length > 1
|
285
|
+
# MAYBE/2017-08-23: Always do this check, not just for help.
|
286
|
+
ambig = MrMurano::Verbose.fancy_ticks(arg)
|
287
|
+
match = arg_opts.map do |opt|
|
288
|
+
opt[:switches].map { |sw| MrMurano::Verbose.fancy_ticks(sw) }.join('|')
|
289
|
+
end
|
290
|
+
match = match.flatten
|
291
|
+
match[-1] = "and #{match[-1]}" if match.length > 1
|
292
|
+
match = match.join(', ')
|
293
|
+
MrMurano::Verbose.error("Ambiguous option: #{ambig} matches: #{match}")
|
294
|
+
exit 2
|
295
|
+
elsif arg_opts.length == 1
|
296
|
+
# See if this option (the only option) has input.
|
297
|
+
arg_opts.first[:switches].any? do |opt|
|
298
|
+
# There may be a space in a --long option, e.g.,
|
299
|
+
# '--config KEY=VAL', which means an argument follows.
|
300
|
+
opt.start_with?('--') && opt.include?(' ')
|
301
|
+
end
|
302
|
+
else
|
303
|
+
false
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
def cleanup_args_simple_command_help
|
251
308
|
# This is a single-word command, e.g., 'link', not 'link list',
|
252
309
|
# as in `murano link --help`, not `murano link list --help`.
|
253
310
|
# Positional parameters break Commander. E.g.,
|
@@ -258,7 +315,6 @@ module Commander
|
|
258
315
|
@args = @args[0..0]
|
259
316
|
# Add back in the --help if the command is not a subcommand help.
|
260
317
|
@args.push('--help') unless active_command.subcmdgrouphelp
|
261
|
-
do_help
|
262
318
|
end
|
263
319
|
|
264
320
|
def show_alias_help_maybe!
|
@@ -21,8 +21,6 @@ module MrMurano
|
|
21
21
|
return [] unless ret.is_a?(Hash) && !ret.key?(:error)
|
22
22
|
return [] unless ret.key?(:items)
|
23
23
|
ret[:items]
|
24
|
-
# MAYBE/2017-08-17:
|
25
|
-
# sort_by_name(ret[:items])
|
26
24
|
end
|
27
25
|
|
28
26
|
def search(svc_name)
|
@@ -33,8 +31,14 @@ module MrMurano
|
|
33
31
|
super(svc_name, path)
|
34
32
|
end
|
35
33
|
|
36
|
-
def fetch(id)
|
37
|
-
|
34
|
+
def fetch(id, _untainted=false, &block)
|
35
|
+
must_id! id
|
36
|
+
get('/' + id.to_s, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
def must_id!(id)
|
40
|
+
return unless id.nil?
|
41
|
+
raise "ID not set, or Service '#{@service_name}' not enabled for this Solution"
|
38
42
|
end
|
39
43
|
|
40
44
|
def scid_for_name(name)
|
@@ -69,21 +73,24 @@ module MrMurano
|
|
69
73
|
)
|
70
74
|
end
|
71
75
|
|
72
|
-
def remove(id)
|
76
|
+
def remove(id, &block)
|
77
|
+
must_id! id
|
73
78
|
return unless remove_item_allowed(id)
|
74
|
-
delete("/#{id}")
|
79
|
+
delete("/#{id}", &block)
|
75
80
|
end
|
76
81
|
|
77
|
-
def info(id=scid)
|
78
|
-
|
82
|
+
def info(id=scid, &block)
|
83
|
+
must_id! id
|
84
|
+
get("/#{id}/info", &block)
|
79
85
|
end
|
80
86
|
|
81
|
-
def logs(id=scid)
|
82
|
-
|
87
|
+
def logs(id=scid, &block)
|
88
|
+
must_id! id
|
89
|
+
get("/#{id}/logs", &block)
|
83
90
|
end
|
84
91
|
|
85
92
|
def call(opid, meth=:get, data=nil, id=scid, &block)
|
86
|
-
|
93
|
+
must_id! id
|
87
94
|
call = "/#{id}/call/#{opid}"
|
88
95
|
debug "Will call: #{call}"
|
89
96
|
case meth
|