MuranoCLI 3.2.0.beta.1 → 3.2.0.beta.5
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/.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
|