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
@@ -0,0 +1,51 @@
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 'uri'
9
+ require 'MrMurano/Config'
10
+ require 'MrMurano/http'
11
+ require 'MrMurano/verbosing'
12
+ require 'MrMurano/SolutionId'
13
+ require 'MrMurano/SyncUpDown'
14
+
15
+ module MrMurano
16
+ ## The details of talking to the Webservice service.
17
+ module Webservice
18
+ class WebserviceBase
19
+ include Http
20
+ include Verbose
21
+ include SolutionId
22
+
23
+ def initialize
24
+ @solntype = 'application.id'
25
+ @uriparts_sidex = 1
26
+ init_sid!
27
+ # FIXME/2017-06-05/MRMUR-XXXX: Update to new endpoint.
28
+ #@uriparts = [:service, @sid, :webservice]
29
+ @uriparts = [:solution, @sid]
30
+ @itemkey = :id
31
+ #@locationbase = $cfg['location.base']
32
+ @location = nil
33
+ end
34
+
35
+ ## Generate an endpoint in Murano
36
+ # Uses the uriparts and path
37
+ # @param path String: any additional parts for the URI
38
+ # @return URI: The full URI for this endpoint.
39
+ def endpoint(path='')
40
+ super
41
+ parts = ['https:/', $cfg['net.host'], 'api:1'] + @uriparts
42
+ s = parts.map(&:to_s).join('/')
43
+ URI(s + path.to_s)
44
+ end
45
+ # …
46
+
47
+ include SyncUpDown
48
+ end
49
+ end
50
+ end
51
+
@@ -1,33 +1,36 @@
1
- require 'MrMurano/commands/assign'
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
+ # DEVs: If you want to generate a completion file, uncomment this.
9
+ # Then run, from the base of the project, e.g.,
10
+ # rake install:user
11
+ # murano completion > docs/completions/murano_completion-bash
12
+ #require 'MrMurano/commands/completion'
13
+
2
14
  require 'MrMurano/commands/business'
3
- require 'MrMurano/commands/businessList'
4
15
  require 'MrMurano/commands/config'
5
16
  require 'MrMurano/commands/content'
6
17
  require 'MrMurano/commands/cors'
18
+ require 'MrMurano/commands/devices'
7
19
  require 'MrMurano/commands/domain'
8
- require 'MrMurano/commands/init'
20
+ require 'MrMurano/commands/globals'
9
21
  require 'MrMurano/commands/keystore'
22
+ require 'MrMurano/commands/init'
23
+ require 'MrMurano/commands/link'
10
24
  require 'MrMurano/commands/login'
11
25
  require 'MrMurano/commands/logs'
12
26
  require 'MrMurano/commands/mock'
13
27
  require 'MrMurano/commands/postgresql'
14
28
  require 'MrMurano/commands/password'
15
- require 'MrMurano/commands/product'
16
- require 'MrMurano/commands/productCreate'
17
- require 'MrMurano/commands/productDelete'
18
- require 'MrMurano/commands/productDevice'
19
- require 'MrMurano/commands/productDeviceIdCmds'
20
- require 'MrMurano/commands/productList'
21
- require 'MrMurano/commands/productWrite'
29
+ require 'MrMurano/commands/settings'
22
30
  require 'MrMurano/commands/show'
23
31
  require 'MrMurano/commands/solution'
24
- require 'MrMurano/commands/solutionCreate'
25
- require 'MrMurano/commands/solutionDelete'
26
- require 'MrMurano/commands/solutionList'
27
32
  require 'MrMurano/commands/status'
28
33
  require 'MrMurano/commands/sync'
29
34
  require 'MrMurano/commands/tsdb'
30
35
  require 'MrMurano/commands/usage'
31
36
 
32
- require 'MrMurano/commands/completion'
33
-
@@ -1,15 +1,309 @@
1
- require 'MrMurano/SubCmdGroupContext'
1
+ # Last Modified: 2017.08.17 /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/verbosing'
9
+ require 'MrMurano/Account'
10
+ require 'MrMurano/Business'
11
+ require 'MrMurano/ReCommander'
12
+
13
+ MSG_BUSINESSES_NONE_FOUND = 'No businesses found' if !defined? MSG_BUSINESSES_NONE_FOUND
14
+
15
+ # *** Base business command help.
16
+ # -------------------------------
2
17
 
3
18
  command :business do |c|
4
- c.syntax = %{murano business}
5
- c.summary = %{About Business}
6
- c.description = %{Sub-commands for working with Businesses}
19
+ c.syntax = %(murano business)
20
+ c.summary = %(About business)
21
+ c.description = %(
22
+ Commands for working with businesses.
23
+ ).strip
24
+ c.project_not_required = true
7
25
 
8
- c.action do |args, options|
26
+ c.action do |_args, _options|
9
27
  ::Commander::UI.enable_paging
10
28
  say MrMurano::SubCmdGroupHelp.new(c).get_help
11
29
  end
12
30
  end
31
+ alias_command 'businesses', 'business'
32
+
33
+ # *** Common business command options.
34
+ # ------------------------------------
35
+
36
+ def cmd_business_add_options(c)
37
+ # MAYBE/2017-08-15: Rename to --id-only.
38
+ c.option '--idonly', 'Only return the IDs'
39
+ c.option '--[no-]brief', 'Show fewer fields: only Business ID and name'
40
+ # LATER/2017-08-17: Move -o to a file with --json, etc. (make
41
+ # easier to use --json/--yaml/--output any file, without
42
+ # having to use obscure `-c tool.outformat=json`).
43
+ c.option '-o', '--output FILE', 'Download to file instead of STDOUT'
44
+ end
45
+
46
+ def cmd_options_add_id_and_name(c)
47
+ c.option '--id', 'Specified argument is an ID'
48
+ c.option '--name', 'Specified argument is a name'
49
+ end
50
+
51
+ def cmd_defaults_id_and_name(options)
52
+ if !options.id.nil? && !options.name.nil?
53
+ MrMurano::Verbose.error('Please only --id or --name but not both')
54
+ exit 1
55
+ end
56
+ end
57
+
58
+ def cmd_verify_args_and_id_or_name!(args, options)
59
+ if !args.any? && (options.id || options.name)
60
+ MrMurano::Verbose.warning(
61
+ 'The --id and --name options only apply when specifying a business name or ID.'
62
+ )
63
+ exit 1
64
+ end
65
+ end
66
+
67
+ def cmd_option_business_pickers(c)
68
+ c.option('--business-id ID', String, %(ID of Murano Business to use))
69
+ c.option('--business-name NAME', String, %(Name of Murano Business to use))
70
+ c.option('--business BUSINESS', String, %(Name or ID of Murano Business to use))
71
+ end
72
+
73
+ def any_business_pickers?(options)
74
+ num_ways = 0
75
+ num_ways += 1 unless options.business_id.to_s.empty?
76
+ num_ways += 1 unless options.business_name.to_s.empty?
77
+ num_ways += 1 unless options.business.to_s.empty?
78
+ #if num_ways > 1
79
+ # MrMurano::Verbose.error(
80
+ # 'Please specify only one of: --business, --business-id, or --business-name'
81
+ # )
82
+ # exit 1
83
+ #end
84
+ num_ways > 0
85
+ end
86
+
87
+ # *** Business commands: list and find.
88
+ # -------------------------------------
89
+
90
+ command 'business list' do |c|
91
+ c.syntax = %(murano business list [--options])
92
+ c.summary = %(List businesses)
93
+ c.description = %(
94
+ List businesses.
95
+ ).strip
96
+ c.project_not_required = true
97
+
98
+ cmd_business_add_options(c)
99
+
100
+ c.action do |args, options|
101
+ c.verify_arg_count!(args)
102
+ cmd_business_find_and_output(args, options)
103
+ end
104
+ end
105
+ alias_command 'businesses list', 'business list'
106
+
107
+ command 'business find' do |c|
108
+ c.syntax = %(murano business find [--options] [<name-or-ID,...>])
109
+ c.summary = %(Find business by name or ID)
110
+ c.description = %(
111
+ Find business by name or ID.
112
+ ).strip
113
+ c.project_not_required = true
114
+
115
+ cmd_business_add_options(c)
116
+
117
+ # Add --business/-id/-name options.
118
+ cmd_option_business_pickers(c)
13
119
 
14
- # vim: set ai et sw=2 ts=2 :
120
+ # Add --id and --name options.
121
+ cmd_options_add_id_and_name(c)
122
+
123
+ c.action do |args, options|
124
+ # SKIP: c.verify_arg_count!(args)
125
+ cmd_defaults_id_and_name(options)
126
+ if !args.any? && !any_business_pickers?(options)
127
+ MrMurano::Verbose.error('What would you like to find?')
128
+ exit 1
129
+ end
130
+ cmd_business_find_and_output(args, options)
131
+ end
132
+ end
133
+
134
+ # *** Business actions helpers.
135
+ # -----------------------------
136
+
137
+ def business_find_or_ask!(acc, options)
138
+ #any_business_pickers?(options)
139
+
140
+ match_bid = options.business_id
141
+ match_name = options.business_name
142
+ match_fuzzy = options.business
143
+
144
+ if !match_bid.to_s.empty? || !match_name.to_s.empty? || !match_fuzzy.to_s.empty?
145
+ biz = business_locate!(acc, match_bid, match_name, match_fuzzy)
146
+ elsif !options.find_only
147
+ ask_user = options.refresh
148
+ biz = business_from_config unless ask_user
149
+ biz = businesses_ask_which(acc) if biz.nil?
150
+ end
151
+
152
+ match_bid = $cfg.set('business.id', nil, :internal)
153
+ match_name = $cfg.set('business.name', nil, :internal)
154
+ match_fuzzy = $cfg.set('business.fuzzy', nil, :internal)
155
+
156
+ biz
157
+ end
158
+
159
+ def business_locate!(acc, match_bid, match_name, match_fuzzy)
160
+ biz = nil
161
+ bizes = acc.businesses(bid: match_bid, name: match_name, fuzzy: match_fuzzy)
162
+ if bizes.count == 1
163
+ biz = bizes.first
164
+ say("Found business #{biz.pretty_name_and_id}")
165
+ puts('')
166
+ elsif bizes.count > 1
167
+ acc.error('More than one matching business was found. Please be more specific.')
168
+ exit(1)
169
+ else
170
+ acc.error('No matching business was found. Please try again.')
171
+ #say('Please visit Exosite.com to view your account and to create a business:')
172
+ #say(" #{MrMurano::SIGN_UP_URL}")
173
+ exit(1)
174
+ end
175
+ biz
176
+ end
177
+
178
+ def business_from_config
179
+ # By default, creating a new Business object loads its ID from the config.
180
+ biz = MrMurano::Business.new
181
+ unless biz.bid.empty?
182
+ # Verify that the business exists.
183
+ MrMurano::Verbose.whirly_start('Verifying Business...')
184
+ biz.overview
185
+ MrMurano::Verbose.whirly_stop
186
+ if biz.valid?
187
+ say("Found Business #{biz.pretty_name_and_id}")
188
+ else
189
+ say("Could not find Business ‘#{biz.bid}’ referenced in the config")
190
+ end
191
+ puts('')
192
+ end
193
+ biz if biz.valid?
194
+ end
195
+
196
+ def businesses_ask_which(acc)
197
+ biz = nil
198
+ bizes = acc.businesses
199
+ if bizes.count == 1
200
+ biz = bizes.first
201
+ say("This user has one business. Using #{biz.pretty_name_and_id}")
202
+ elsif bizes.count.zero?
203
+ MrMurano::Verbose.warning('This user has not created any businesses.')
204
+ say('Please log on to exosite.com to create a free account. Visit:')
205
+ say(" #{MrMurano::SIGN_UP_URL}")
206
+ exit 3
207
+ else
208
+ choose do |menu|
209
+ menu.prompt = 'Please select the Business to use:'
210
+ menu.flow = :columns_across
211
+ bizes.sort_by(&:name).each do |choice|
212
+ menu.choice(choice.name) do
213
+ biz = choice
214
+ end
215
+ end
216
+ end
217
+ end
218
+ puts('')
219
+ biz
220
+ end
221
+
222
+ def cmd_business_find_and_output(args, options)
223
+ cmd_verify_args_and_id_or_name!(args, options)
224
+ acc = MrMurano::Account.instance
225
+ bizz = cmd_business_find_businesses(acc, args, options)
226
+ if bizz.empty? && !options.idonly
227
+ MrMurano::Verbose.error(MSG_BUSINESSES_NONE_FOUND)
228
+ exit 0
229
+ end
230
+ cmd_business_output_businesses(acc, bizz, options)
231
+ end
232
+
233
+ def cmd_business_find_businesses(acc, args, options)
234
+ bid = []
235
+ name = []
236
+ fuzzy = []
237
+
238
+ if args.any?
239
+ flattened = args.map { |cell| cell.split(',') }.flatten
240
+ if options.id
241
+ bid += flattened
242
+ elsif options.name
243
+ name += flattened
244
+ else
245
+ fuzzy += flattened
246
+ end
247
+ end
248
+
249
+ if any_business_pickers?(options)
250
+ if options.business_id
251
+ bid += [options.business_id]
252
+ elsif options.business_name
253
+ name += [options.business_name]
254
+ elsif options.business
255
+ fuzzy += [options.business]
256
+ end
257
+ end
258
+
259
+ MrMurano::Verbose.whirly_start 'Looking for businesses...'
260
+ bizz = acc.businesses(bid: bid, name: name, fuzzy: fuzzy)
261
+ MrMurano::Verbose.whirly_stop
262
+
263
+ bizz
264
+ end
265
+
266
+ def cmd_business_output_businesses(acc, bizz, options)
267
+ if options.idonly
268
+ headers = [:bizid]
269
+ bizz = bizz.map(&:bizid)
270
+ elsif options.brief
271
+ #headers = %i[bizid role name]
272
+ #bizz = bizz.map { |biz| [biz.bizid, biz.role, biz.name] }
273
+ headers = %i[bizid name]
274
+ bizz = bizz.map { |biz| [biz.bizid, biz.name] }
275
+ else
276
+ # 2017-08-16: There are only 3 keys: bizid, role, and name.
277
+ headers = bizz[0].meta.keys
278
+ headers.sort_by! do |hdr|
279
+ case hdr
280
+ when :bizid
281
+ 0
282
+ when :role
283
+ 1
284
+ when :name
285
+ 2
286
+ else
287
+ 3
288
+ end
289
+ end
290
+ bizz = bizz.map { |biz| headers.map { |key| biz.meta[key] } }
291
+ end
292
+
293
+ io = File.open(options.output, 'w') if options.output
294
+ acc.outf(bizz, io) do |dd, ios|
295
+ if options.idonly
296
+ ios.puts dd.join(' ')
297
+ else
298
+ acc.tabularize(
299
+ {
300
+ headers: headers.map(&:to_s),
301
+ rows: dd,
302
+ },
303
+ ios,
304
+ )
305
+ end
306
+ end
307
+ io.close unless io.nil?
308
+ end
15
309
 
@@ -0,0 +1,166 @@
1
+ #!/bin/bash
2
+ # Bash completion (compspec) for <%= program :name %>.
3
+ # vim: set ai et sw=2 ts=2 ft=bash
4
+ # #ft=eruby
5
+
6
+ #__<%= program :name %>_common_options=(
7
+ __app_switches=(
8
+ <% for option in @options -%>
9
+ <%- if flatswitches(option).count > 1 -%>
10
+ <%= flatswitches(option)[1] %>
11
+ <%- else -%>
12
+ <%= flatswitches(option).first %>
13
+ <%- end -%>
14
+ <%- end -%>
15
+ )
16
+
17
+ # Util. fcn.
18
+ function contains_element () {
19
+ local e
20
+ for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
21
+ return 1
22
+ }
23
+
24
+ # Completion "main".
25
+ function _<%= program :name %> () {
26
+ #local cmd0="${1##*/}"
27
+ local cmd0=""
28
+ local cmd1=""
29
+ local cmd2=""
30
+ #local -a cmdn
31
+ local last="${COMP_WORDS[COMP_CWORD]}"
32
+ local line="${COMP_LINE}"
33
+ local -a used_switches
34
+
35
+ local len=$(($COMP_CWORD - 1))
36
+ local idx
37
+ for ((idx=1; idx<=len; idx++)); do
38
+ local cur="${COMP_WORDS[$idx]}"
39
+ # If positional argument is not a flag, it's the command or subcommand.
40
+ if [[ $cur != -* ]]; then
41
+ if [[ -z $cmd0 ]]; then
42
+ cmd0="$cur"
43
+ elif [[ -z $cmd1 ]]; then
44
+ cmd1="$cur"
45
+ elif [[ -z $cmd2 ]]; then
46
+ cmd2="$cur"
47
+ #else
48
+ # cmdn+=("$cur")
49
+ fi
50
+ else
51
+ used_switches+=("$cur")
52
+ fi
53
+ done
54
+ #>&2 echo -e "\ncmd0=$cmd0 / cmd1=$cmd1 / cmd2=$cmd2 / len=$len"
55
+
56
+ if [[ -z $cmd0 ]]; then
57
+ local -a comp_list
58
+ comp_list=(
59
+ <%- for name, subs in cmdTree -%>
60
+ <%= name %>
61
+ <%-end-%>
62
+ )
63
+
64
+ for ((idx = 0; idx < ${#__app_switches[@]}; idx++)); do
65
+ local switch=${__app_switches[$idx]}
66
+ if ! contains_element "$switch" "${used_switches[@]}"; then
67
+ comp_list+=("$switch")
68
+ fi
69
+ done
70
+ COMPREPLY=($(compgen -W '${comp_list[@]}' -- "$last"))
71
+ else
72
+ case $cmd0 in
73
+ <%- for name, subs in cmdTree -%>
74
+ (<%= name %>)
75
+ __<%=program :name%>-<%= name %> "$cmd1" "$cmd2" "${used_switches[@]}"
76
+ ;;
77
+ <%-end-%>
78
+ esac
79
+ fi
80
+ }
81
+
82
+ <%- for name, subs in cmdTree -%>
83
+ <%- command = subs["\0cmd"]; subs = subs.reject{|k,_| k == "\0cmd"} -%>
84
+ # Completion for subcommand: "<%= name %>".
85
+ function __<%=program :name%>-<%= name %> () {
86
+ local subcmd1="$1"
87
+ local subcmd2="$2"
88
+ #local subcmdn="$3"
89
+ local used_switches="${@:3}"
90
+ local last="${COMP_WORDS[COMP_CWORD]}"
91
+ local len=$(($COMP_CWORD - 1))
92
+
93
+ local -a more_switches
94
+
95
+ local -a comp_list
96
+
97
+ #>&2 echo -e "\nsubcmd1=$subcmd1 / subcmd2=$subcmd2 / last=$last / len=$len"
98
+ #>&2 echo "used_switches=$used_switches"
99
+ #>&2 echo "more_switches=$more_switches"
100
+
101
+ # NOTE: Not doing anything special for ${subcmd2}.
102
+ # Are there sub-sub-commands we shoud list?
103
+ <%- unless subs.empty? -%>
104
+ if [[ -z ${subcmd1} || ${len} -eq 1 ]]; then
105
+ comp_list=(
106
+ <%- for sname, ssubs in subs -%>
107
+ <%=sname%>
108
+ <%-end-%>
109
+ )
110
+ else
111
+ case $subcmd1 in
112
+ <%- for sname, ssubs in subs -%>
113
+ <%- command = ssubs["\0cmd"]; subs = ssubs.reject{|k,_| k == "\0cmd"} -%>
114
+ (<%=sname%>)
115
+ more_switches=(
116
+ <%- unless command.nil? or command.options.empty? then -%>
117
+ <%- if flatswitches(option).count > 1 -%>
118
+ {<%= flatswitches(option)[1] %>}
119
+ <%- else -%>
120
+ <%= flatswitches(option).first %>
121
+ <%- end -%>
122
+ <%- end -%>
123
+ )
124
+ ;;
125
+ <%-end-%>
126
+ esac
127
+ fi
128
+ <%-end-%>
129
+
130
+ # Add unused application-wide flags.
131
+ local idx
132
+ for ((idx = 0; idx < ${#__app_switches[@]}; idx++)); do
133
+ local switch=${__app_switches[$idx]}
134
+ if ! contains_element "$switch" "${used_switches[@]}"; then
135
+ comp_list+=("$switch")
136
+ fi
137
+ done
138
+ # Add unused subcommand flags.
139
+ for ((idx = 0; idx < ${#more_switches[@]}; idx++)); do
140
+ local switch=${more_switches[$idx]}
141
+ comp_list+=("$switch")
142
+ done
143
+
144
+ # If there are only --flags, <TAB> will put the common prefix,
145
+ # "--", but maybe the user doesn't want to add a flag after all.
146
+ if [[ -z ${last} ]]; then
147
+ local flags_only=true
148
+ for ((idx = 0; idx < ${#comp_list[@]}; idx++)); do
149
+ local switch=${comp_list[$idx]}
150
+ if [[ ${switch} != --* ]]; then
151
+ flags_only=false
152
+ break
153
+ fi
154
+ done
155
+ if ${flags_only}; then
156
+ # Use two Unicode en spaces to prevent compgen from prefixing "--".
157
+ comp_list+=("  ")
158
+ fi
159
+ fi
160
+
161
+ COMPREPLY=($(compgen -W '${comp_list[@]}' -- "${last}"))
162
+ }
163
+
164
+ <%- end -%>
165
+ complete -F _murano murano
166
+