hammer_cli 0.19.1 → 2.2.0

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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/bin/hammer-complete +28 -0
  3. data/config/cli_config.template.yml +2 -0
  4. data/config/hammer.completion +5 -0
  5. data/doc/commands_extension.md +12 -0
  6. data/doc/creating_commands.md +100 -0
  7. data/doc/installation.md +47 -4
  8. data/doc/installation_rpm.md +2 -2
  9. data/doc/release_notes.md +31 -6
  10. data/lib/hammer_cli.rb +1 -0
  11. data/lib/hammer_cli/abstract.rb +61 -4
  12. data/lib/hammer_cli/apipie/api_connection.rb +5 -1
  13. data/lib/hammer_cli/apipie/command.rb +3 -2
  14. data/lib/hammer_cli/apipie/option_builder.rb +15 -13
  15. data/lib/hammer_cli/apipie/option_definition.rb +9 -7
  16. data/lib/hammer_cli/bash.rb +2 -0
  17. data/lib/hammer_cli/bash/completion.rb +159 -0
  18. data/lib/hammer_cli/bash/prebuild_command.rb +21 -0
  19. data/lib/hammer_cli/command_extensions.rb +21 -1
  20. data/lib/hammer_cli/connection.rb +4 -0
  21. data/lib/hammer_cli/exception_handler.rb +11 -2
  22. data/lib/hammer_cli/full_help.rb +8 -1
  23. data/lib/hammer_cli/help/builder.rb +29 -3
  24. data/lib/hammer_cli/logger_watch.rb +1 -1
  25. data/lib/hammer_cli/main.rb +5 -3
  26. data/lib/hammer_cli/options/normalizers.rb +7 -3
  27. data/lib/hammer_cli/options/option_definition.rb +26 -6
  28. data/lib/hammer_cli/options/option_family.rb +114 -0
  29. data/lib/hammer_cli/options/predefined.rb +1 -1
  30. data/lib/hammer_cli/output/adapter/abstract.rb +1 -5
  31. data/lib/hammer_cli/output/adapter/base.rb +1 -1
  32. data/lib/hammer_cli/output/adapter/csv.rb +3 -2
  33. data/lib/hammer_cli/output/adapter/json.rb +14 -3
  34. data/lib/hammer_cli/output/adapter/silent.rb +1 -1
  35. data/lib/hammer_cli/output/adapter/table.rb +27 -8
  36. data/lib/hammer_cli/output/adapter/yaml.rb +6 -3
  37. data/lib/hammer_cli/output/output.rb +2 -4
  38. data/lib/hammer_cli/settings.rb +2 -1
  39. data/lib/hammer_cli/subcommand.rb +25 -1
  40. data/lib/hammer_cli/testing/command_assertions.rb +2 -2
  41. data/lib/hammer_cli/utils.rb +22 -0
  42. data/lib/hammer_cli/version.rb +1 -1
  43. data/locale/ca/LC_MESSAGES/hammer-cli.mo +0 -0
  44. data/locale/de/LC_MESSAGES/hammer-cli.mo +0 -0
  45. data/locale/en/LC_MESSAGES/hammer-cli.mo +0 -0
  46. data/locale/en_GB/LC_MESSAGES/hammer-cli.mo +0 -0
  47. data/locale/es/LC_MESSAGES/hammer-cli.mo +0 -0
  48. data/locale/fr/LC_MESSAGES/hammer-cli.mo +0 -0
  49. data/locale/it/LC_MESSAGES/hammer-cli.mo +0 -0
  50. data/locale/ja/LC_MESSAGES/hammer-cli.mo +0 -0
  51. data/locale/ko/LC_MESSAGES/hammer-cli.mo +0 -0
  52. data/locale/pt_BR/LC_MESSAGES/hammer-cli.mo +0 -0
  53. data/locale/ru/LC_MESSAGES/hammer-cli.mo +0 -0
  54. data/locale/zh_CN/LC_MESSAGES/hammer-cli.mo +0 -0
  55. data/locale/zh_TW/LC_MESSAGES/hammer-cli.mo +0 -0
  56. data/test/unit/abstract_test.rb +23 -2
  57. data/test/unit/apipie/api_connection_test.rb +1 -0
  58. data/test/unit/apipie/option_builder_test.rb +8 -0
  59. data/test/unit/bash_test.rb +138 -0
  60. data/test/unit/command_extensions_test.rb +67 -49
  61. data/test/unit/exception_handler_test.rb +44 -0
  62. data/test/unit/help/builder_test.rb +22 -0
  63. data/test/unit/options/option_family_test.rb +48 -0
  64. data/test/unit/output/adapter/base_test.rb +58 -0
  65. data/test/unit/output/adapter/csv_test.rb +63 -1
  66. data/test/unit/output/adapter/json_test.rb +61 -0
  67. data/test/unit/output/adapter/table_test.rb +70 -1
  68. data/test/unit/output/adapter/yaml_test.rb +59 -0
  69. data/test/unit/output/output_test.rb +3 -3
  70. metadata +17 -6
  71. data/hammer_cli_complete +0 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fba56b0d34d9914c40df8f424e68d9268d7e2a38e5f2dd421e10991f477fbd1d
4
- data.tar.gz: 5b1e6d8ea29af809ab09884cc2579c3f328439a7d102335940820bd32ec3289d
3
+ metadata.gz: d903c3dbbe33a2411dfd2e23b781609a40b39b4ed29066cabe35af22335042d5
4
+ data.tar.gz: 25acdf29e7a071a945a4c7c2c4745083e0e11e7d12ce098c662054a7d87caeb1
5
5
  SHA512:
6
- metadata.gz: 7fdb4ed23030a8d87156504452c1b04959dd466015579ec2dec75b548bd5af2baea8a5538f0d4b866a2038addf2034c9df2bd89dc709378b275868e6c48c9e99
7
- data.tar.gz: 45d29077823ab5997435b51f4cfab81a4c1373cd42793958811cf7ec48ab5837f48779b4ab237af9b980aca43dd43b685b2197e3f485dfc4894421098898c5f3
6
+ metadata.gz: 8a117c635359bc261f70cb67bf33fc2080f15b909981a98f87d7c64235a2ecf686bf1530b5293e60565e5e52cab2ed9bbf17f604816099ada8e11b11a5b7f064
7
+ data.tar.gz: 3e296e36f46d6374fc1878a51447cd2fe820104fa5ba191c6bde91a62aff2fd7b76e12743d152ca0eb9457b541e38dd39351da138020501d286c3af071e33b39
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'English'
4
+ @project_root = File.expand_path('../..', __FILE__)
5
+ $LOAD_PATH.unshift(File.join(@project_root, 'lib'))
6
+ HAMMER = ENV['HAMMER'] || File.join(@project_root, 'bin/hammer')
7
+
8
+ require 'yaml'
9
+
10
+ completion_cache_file = ENV['HAMMER_COMPLETION_CACHE'] || '~/.cache/hammer_completion.yml'
11
+ completion_cache_file = File.expand_path(completion_cache_file)
12
+
13
+ # build the cache if it does not exist
14
+ unless File.exist?(completion_cache_file)
15
+ require 'hammer_cli'
16
+ `#{HAMMER} prebuild-bash-completion`
17
+ end
18
+
19
+ require 'hammer_cli/bash/completion'
20
+
21
+ dict = HammerCLI::Bash::Completion.load_description(completion_cache_file)
22
+
23
+ comp_line = ENV['COMP_LINE'] || ''
24
+ comp_args = comp_line.split(' ', 2).last || ''
25
+
26
+ result = HammerCLI::Bash::Completion.new(dict).complete(comp_args)
27
+
28
+ puts result.join("\n")
@@ -44,6 +44,8 @@
44
44
  # Log record pattern (logging gem syntax)
45
45
  #:log_pattern: '[%5l %d %c] %m'
46
46
 
47
+ # Location of cache for bash completion
48
+ :completion_cache_file: '~/.cache/hammer_completion.yml'
47
49
 
48
50
  # SSL auth options
49
51
  #:ssl:
@@ -0,0 +1,5 @@
1
+ #
2
+ # Hammer CLI bash completion script
3
+ #
4
+
5
+ complete -C hammer-complete -o nospace hammer
@@ -10,6 +10,11 @@ Each command can be easily extended with one ore more `HammerCLI::CommandExtensi
10
10
  inheritable true
11
11
  # Simply add a new option to a command is being extended
12
12
  option(option_params)
13
+ # Add option family to a command
14
+ option_family(common_options = {}) do
15
+ parent option_params
16
+ child option_params
17
+ end
13
18
  # Extend hash with data returned from server before it is printed
14
19
  before_print do |data|
15
20
  # data modifications
@@ -65,6 +70,13 @@ class MyCommandExtensions < HammerCLI::CommandExtensions
65
70
 
66
71
  option ['--new-option'], 'TYPE', _('Option description')
67
72
 
73
+ option_family(
74
+ description: _('Common description')
75
+ ) do
76
+ parent ['--new-option'], 'TYPE', _('Option description')
77
+ child ['--new-option-ver2'], 'TYPE', _('Option description')
78
+ end
79
+
68
80
  before_print do |data|
69
81
  data['results'].each do |result|
70
82
  result['status'] = process_errors(result['errors'])
@@ -173,6 +173,54 @@ Here is the list of predefined options:
173
173
  * `:fields` Expects a list with fields to show in output, see [example](creating_commands.md#printing-hash-records).
174
174
 
175
175
 
176
+ ### Option family
177
+ Option family is the way to unify options which have the same meaning or purpose,
178
+ but contain some differences in their definitions (e.g. the name/switch of an option).
179
+ Mainly serves as a container for options, which purpose is to show less repetitive
180
+ output in commands' help. Option builders use it by default.
181
+
182
+ To define an option family, use the following DSL:
183
+ ```ruby
184
+ # options is a Hash with options for family/each defined option within it
185
+ option_family(options = {}) do
186
+ # parent is the main option. Must be single, option family can have only one parent.
187
+ parent switches, type, description, options
188
+ # child is an additional option. Could be none or more than one. Aren't shown in the help output.
189
+ child switches, type, description, options
190
+ end
191
+ ```
192
+
193
+ ##### Example
194
+
195
+ ```ruby
196
+ option_family(
197
+ aliased_resource: 'environment',
198
+ description: _('Puppet environment'),
199
+ deprecation: _("Use %s instead") % '--puppet-environment[-id]'
200
+ deprecated: { '--environment' => _("Use %s instead") % '--puppet-environment[-id]',
201
+ '--environment-id' => _("Use %s instead") % '--puppet-environment[-id]'}
202
+ ) do
203
+ parent '--environment-id', 'ENVIRONMENT_ID', _(''),
204
+ format: HammerCLI::Options::Normalizers::Number.new,
205
+ attribute_name: :option_environment_id
206
+ child '--environment', 'ENVIRONMENT_NAME', _('Environment name'),
207
+ attribute_name: :option_environment_name
208
+ end
209
+
210
+ # $ hammer command --help:
211
+ # ...
212
+ # Options:
213
+ # --environment[-id] Puppet environment (Deprecated: Use --puppet-environment[-id] instead)
214
+ # ...
215
+
216
+ # $ hammer full-help:
217
+ # ...
218
+ # Options:
219
+ # --environment ENVIRONMENT_NAME Environment name (--environment is deprecated: Use --puppet-environment[-id] instead)
220
+ # --environment-id ENVIRONMENT_ID (--environment-id is deprecated: Use --puppet-environment[-id] instead)
221
+ # ...
222
+ ```
223
+
176
224
  ### Option builders
177
225
  Hammer commands offer option builders that can be used for automatic option generation.
178
226
  See [documentation page](option_builders.md#option-builders) dedicated to this topic for more details.
@@ -406,6 +454,31 @@ Options:
406
454
  -h, --help print help
407
455
  ```
408
456
 
457
+ #### Aliasing subcommands
458
+
459
+ Commands can have two or more names, e.g. aliases. To support such functionality
460
+ simple name addition could be used via `command_name` or `command_names` method:
461
+ ```ruby
462
+ module HammerCLIHello
463
+
464
+ class SayCommand < HammerCLI::AbstractCommand
465
+
466
+ class GreetingsCommand < HammerCLI::AbstractCommand
467
+ command_name 'hello'
468
+ command_name 'hi'
469
+ # or use can use other method:
470
+ command_names 'hello', 'hi'
471
+
472
+ desc 'Say Hello World!'
473
+ # ...
474
+ end
475
+
476
+ autoload_subcommands
477
+ end
478
+
479
+ HammerCLI::MainCommand.subcommand 'say', "Say something", HammerCLIHello::SayCommand
480
+ end
481
+ ```
409
482
 
410
483
  ### Conflicting subcommands
411
484
  It can happen that two different plugins define subcommands with the same name by accident.
@@ -494,6 +567,33 @@ You first create an _output definition_ that you apply to your data. The result
494
567
  is a collection of fields, each having its type. The collection is then passed to an
495
568
  _output adapter_ which handles the actual formatting and printing.
496
569
 
570
+ Adapters support printing by chunks, e.g. if you want to print a large set of
571
+ data (1000+ records), but you make several calls to the server instead of one,
572
+ you may want to print received data right away instead of waiting for the rest.
573
+ This can be achieved via `:current_chunk` option for
574
+ `print_collection` and `print_data` methods. Allowed values for `:current_chunk`
575
+ are `:first`, `:another`, `:last`. By default adapters use `:single` value that
576
+ means only one record will be printed.
577
+
578
+ ##### Printing by chunks
579
+ ```ruby
580
+ # ...
581
+ def execute
582
+ loop do
583
+ # ...
584
+ data = send_request
585
+ print_data(data, current_chunk: :first)
586
+ # ...
587
+ data = send_request
588
+ print_data(data, current_chunk: :another)
589
+ # ...
590
+ data = send_request
591
+ print_data(data, current_chunk: :last)
592
+ end
593
+ end
594
+ # ...
595
+ ```
596
+
497
597
  Hammer provides a DSL for defining the output. Next rather complex example will
498
598
  explain how to use it in action.
499
599
 
@@ -132,8 +132,51 @@ And you are done. Your hammer client is configured and ready to use.
132
132
  Autocompletion
133
133
  --------------
134
134
 
135
- It is necessary to copy the hammer_cli_complete script to the bash_completion.d directory.
136
-
137
- $ sudo cp hammer-cli/hammer_cli_complete /etc/bash_completion.d/
135
+ The completion offers suggestion of possible command-line subcommands and their
136
+ options as usual. It can also suggest values for options and params where file
137
+ or directory path is expected.
138
+
139
+ Bash completion is automatically installed by RPM. To use it for development
140
+ setup `cp ./config/hammer.completion /etc/bash_completion.d/hammer` and load it
141
+ to the current shell `source /etc/bash_completion.d/hammer`. Make sure
142
+ the `$PWD/bin` is in `PATH` or there is full path to `hammer-complete`
143
+ executable specified in `/etc/bash_completion.d/hammer`.
144
+
145
+ Bash completion for hammer needs pre-built cache that holds description of
146
+ all subcommands and its parameters. The cache is located by default in
147
+ `~/.cache/hammer_completion.yml`. The location can be changed in hammer's
148
+ config file. The cache can be built manually with
149
+ `hammer prebuild-bash-completion` or is built automatically when completion is
150
+ used and the cache is missing (this may cause slight delay). The cache expires
151
+ if your API cache was changed (it indicates that the features on the instance
152
+ may have changed which has impact on hammer CLI options and subcommands).
153
+
154
+ #### Available value types
155
+
156
+ Completion of values is dependent on CLI option and prameter settings, e.g.:
157
+
158
+ ```ruby
159
+ option '--value', 'VALUE', 'One of a, b, c', completion: { type: :enum, values: %w[a b c] }
160
+ ```
138
161
 
139
- Then after starting a new shell the completion should work.
162
+ Possible options for the `:completion` attribute are:
163
+ - `{ type: :flag }` option has no value, default for flags.
164
+ - `{ type: :value }` option has value of unknown type, no suggestions for the
165
+ value, default.
166
+ - `{ type: :list }` option has value of list type, no suggestions for the
167
+ value.
168
+ - `{ type: :key_value_list }` option has value of key=value list type, no
169
+ suggestions for the value.
170
+ - `{ type: :directory }` value is directory, suggestions follow directory
171
+ structure.
172
+ - `{ type: :file, filter: '\.txt$' }` value is file, suggestions follow
173
+ directory structure, optional `:filter` is regexp to filter the results.
174
+ - `{ type: :enum, values: ['first', 'second']}` option can have one of the
175
+ listed values, suggestions follow specified `values`.
176
+ - `{ type: :multienum, values: ['first', 'second']}` option can have one or
177
+ more of the listed values, suggestions follow specified `values`.
178
+ - `{ type: :schema, schema: 'a=int\,b=string' }` option should have value
179
+ according to specified schema, suggestion is the specified schema.
180
+
181
+ All those completion attributes are generated automatically, specify you own to
182
+ override.
@@ -1,8 +1,8 @@
1
1
  ### Installation from RPMs
2
2
 
3
- #### Step 1: setup yum repositories
3
+ #### Step 1: set up yum repositories
4
4
 
5
- For Foreman 1.3 stable the hammer packages are part of your installation repo and you can skip this step.
5
+ For Foreman 1.3 stable, the hammer packages are part of your installation repo and you can skip this step.
6
6
 
7
7
  You can choose from stable or nightly repo. Nightly has more recent version of hammer packages, but it was subject to less testing so there is a higher risk of issues.
8
8
  Add the Foreman yum repository to your yum repo files. For Fedora installations replace 'el6' with 'f18' or 'f19' as appropriate.
@@ -1,15 +1,40 @@
1
1
  Release notes
2
2
  =============
3
- ### 0.19.1 (2019-12-31)
3
+ ### 2.2.0 (2020-08-11)
4
+ * Update installation_rpm.md ([PR #333](https://github.com/theforeman/hammer-cli/pull/333))
5
+ * Clean gem_release.ipynb up
6
+ * Replace awesome_print with amazing_print ([PR #330](https://github.com/theforeman/hammer-cli/pull/330)), [#29846](http://projects.theforeman.org/issues/29846)
7
+ * Fix typo: s/filed/feild/ ([PR #331](https://github.com/theforeman/hammer-cli/pull/331))
8
+ * Bump to 2.2.0-develop
9
+
10
+ ### 2.1.0 (2020-05-14)
11
+ * Hammer full-help returns correct output, [#29697](http://projects.theforeman.org/issues/29697)
12
+ * Add fuzzy subcommand matching, [#29413](http://projects.theforeman.org/issues/29413)
13
+ * Help contains squeezed options, [#28440](http://projects.theforeman.org/issues/28440)
14
+ * Keep referenced resource in option options, [#29015](http://projects.theforeman.org/issues/29015)
15
+ * Bump to 2.1.0-develop
16
+
17
+ ### 2.0.0 (2020-02-12)
18
+ * Bump version to 2.0.0
19
+ * Bump version to 2.0 ([PR #324](https://github.com/theforeman/hammer-cli/pull/324))
20
+ * Better promts for missing arguments, [#28793](http://projects.theforeman.org/issues/28793)
4
21
  * Allow column max width more than 80, [#28503](http://projects.theforeman.org/issues/28503)
22
+ * Remove computing sha, [#27728](http://projects.theforeman.org/issues/27728)
23
+ * Fixed userdata false display in image list, [#28134](http://projects.theforeman.org/issues/28134)
24
+ * Add new bash completion, [#27728](http://projects.theforeman.org/issues/27728)
25
+ * Allow adapters print page by page, [#17819](http://projects.theforeman.org/issues/17819)
26
+ * Add release documentation ([PR #317](https://github.com/theforeman/hammer-cli/pull/317)), [#28149](http://projects.theforeman.org/issues/28149)
27
+ * Fix pr links in release notes ([PR #318](https://github.com/theforeman/hammer-cli/pull/318)), [#28202](http://projects.theforeman.org/issues/28202)
5
28
  * Extract table generator into reusable component ([PR #314](https://github.com/theforeman/hammer-cli/pull/314)), [#27318](http://projects.theforeman.org/issues/27318)
29
+ * Better prompts for missing arguments ([PR #313](https://github.com/theforeman/hammer-cli/pull/313)), [#27595](http://projects.theforeman.org/issues/27595)
30
+ * Bump to 0.20-develop
6
31
 
7
32
  ### 0.19.0 (2019-10-26)
8
- * Allow schema building for custom options ([PR #316](https://github.com/Apipie/apipie-bindings/pull/316)), [#27899](http://projects.theforeman.org/issues/27899)
9
- * New lines in text attr dont break output ([PR #300](https://github.com/Apipie/apipie-bindings/pull/300)), [#25878](http://projects.theforeman.org/issues/25878)
10
- * Added error to wrong --output ([PR #315](https://github.com/Apipie/apipie-bindings/pull/315)), [#21590](http://projects.theforeman.org/issues/21590)
11
- * Pr review checklist ([PR #305](https://github.com/Apipie/apipie-bindings/pull/305)), [#26950](http://projects.theforeman.org/issues/26950)
12
- * List items in help with customization ([PR #309](https://github.com/Apipie/apipie-bindings/pull/309)), [#27237](http://projects.theforeman.org/issues/27237)
33
+ * Allow schema building for custom options ([PR #316](https://github.com/theforeman/hammer-cli/pull/316)), [#27899](http://projects.theforeman.org/issues/27899)
34
+ * New lines in text attr dont break output ([PR #300](https://github.com/theforeman/hammer-cli/pull/300)), [#25878](http://projects.theforeman.org/issues/25878)
35
+ * Added error to wrong --output ([PR #315](https://github.com/theforeman/hammer-cli/pull/315)), [#21590](http://projects.theforeman.org/issues/21590)
36
+ * Pr review checklist ([PR #305](https://github.com/theforeman/hammer-cli/pull/305)), [#26950](http://projects.theforeman.org/issues/26950)
37
+ * List items in help with customization ([PR #309](https://github.com/theforeman/hammer-cli/pull/309)), [#27237](http://projects.theforeman.org/issues/27237)
13
38
 
14
39
  ### 0.18.0 (2019-08-01)
15
40
  * Unsure minimal label length ([PR #310](https://github.com/theforeman/hammer-cli/pull/310)) ([#26960](http://projects.theforeman.org/issues/26960))
@@ -23,3 +23,4 @@ require 'hammer_cli/apipie'
23
23
  require 'hammer_cli/shell'
24
24
  require 'hammer_cli/defaults'
25
25
  require 'hammer_cli/full_help'
26
+ require 'hammer_cli/bash'
@@ -13,6 +13,7 @@ require 'hammer_cli/options/predefined'
13
13
  require 'hammer_cli/help/builder'
14
14
  require 'hammer_cli/help/text_builder'
15
15
  require 'hammer_cli/command_extensions'
16
+ require 'hammer_cli/options/option_family'
16
17
  require 'logging'
17
18
 
18
19
  module HammerCLI
@@ -74,6 +75,7 @@ module HammerCLI
74
75
  begin
75
76
  begin
76
77
  exit_code = super
78
+ context.delete(:fields)
77
79
  raise "exit code must be integer" unless exit_code.is_a? Integer
78
80
  rescue => e
79
81
  exit_code = handle_exception(e)
@@ -190,10 +192,21 @@ module HammerCLI
190
192
  # skip switches that are already defined
191
193
  next if option.nil? or option.switches.any? {|s| find_option(s) }
192
194
 
195
+ if option.respond_to?(:referenced_resource)
196
+ # Collect options that don't have family, but related to this parent.
197
+ children = find_options(
198
+ referenced_resource: option.referenced_resource.to_s,
199
+ aliased_resource: option.aliased_resource.to_s
200
+ ).select { |o| o.family.nil? || o.family.head.nil? }
201
+ children.each do |child|
202
+ option.family.adopt(child) if option.family
203
+ end
204
+ end
193
205
  declared_options << option
194
206
  block ||= option.default_conversion_block
195
207
  define_accessors_for(option, &block)
196
208
  extend_options_help(option) if option.value_formatter.is_a?(HammerCLI::Options::Normalizers::ListNested)
209
+ completion_type_for(option)
197
210
  end
198
211
  end
199
212
 
@@ -205,6 +218,7 @@ module HammerCLI
205
218
  extension.delegatee(self)
206
219
  extension.extend_predefined_options(self)
207
220
  extension.extend_options(self)
221
+ extension.extend_option_family(self)
208
222
  extension.extend_output(self)
209
223
  extension.extend_help(self)
210
224
  logger('Extensions').info "Applied #{extension.details} on #{self}."
@@ -220,6 +234,12 @@ module HammerCLI
220
234
 
221
235
  protected
222
236
 
237
+ def self.option_family(options = {}, &block)
238
+ options[:creator] ||= self
239
+ family = HammerCLI::Options::OptionFamily.new(options)
240
+ family.instance_eval(&block)
241
+ end
242
+
223
243
  def self.find_options(switch_filter, other_filters={})
224
244
  filters = other_filters
225
245
  if switch_filter.is_a? Hash
@@ -242,8 +262,8 @@ module HammerCLI
242
262
  output.print_record(definition, record)
243
263
  end
244
264
 
245
- def print_collection(definition, collection)
246
- output.print_collection(definition, collection)
265
+ def print_collection(definition, collection, options = {})
266
+ output.print_collection(definition, collection, options)
247
267
  end
248
268
 
249
269
  def print_message(msg, msg_params = {}, options = {})
@@ -283,8 +303,17 @@ module HammerCLI
283
303
  end
284
304
 
285
305
  def self.command_name(name=nil)
286
- @name = name if name
287
- @name || (superclass.respond_to?(:command_name) ? superclass.command_name : nil)
306
+ if @names && name
307
+ @names << name if !@names.include?(name)
308
+ else
309
+ @names = [name] if name
310
+ end
311
+ @names || (superclass.respond_to?(:command_names) ? superclass.command_names : nil)
312
+ end
313
+
314
+ def self.command_names(*names)
315
+ @names = names unless names.empty?
316
+ @names || (superclass.respond_to?(:command_names) ? superclass.command_names : nil)
288
317
  end
289
318
 
290
319
  def self.warning(message = nil)
@@ -314,6 +343,7 @@ module HammerCLI
314
343
  declared_options << option
315
344
  block ||= option.default_conversion_block
316
345
  define_accessors_for(option, &block)
346
+ completion_type_for(option, opts)
317
347
  end
318
348
  extend_options_help(option) if option.value_formatter.is_a?(HammerCLI::Options::Normalizers::ListNested)
319
349
  option
@@ -352,6 +382,33 @@ module HammerCLI
352
382
  sources
353
383
  end
354
384
 
385
+ def self.completion_map
386
+ completion = {}
387
+ # collect options
388
+ recognised_options.each do |opt|
389
+ opt.switches.each do |switch|
390
+ completion[switch] = completion_types.fetch(switch, {})
391
+ end
392
+ end
393
+ # collect subcommands recursively
394
+ recognised_subcommands.each do |cmd|
395
+ completion[cmd.names.first] = cmd.subcommand_class.completion_map
396
+ end
397
+ # collect params
398
+ completion[:params] = completion_types[:params] unless completion_types[:params].empty?
399
+ completion
400
+ end
401
+
402
+ def self.completion_types
403
+ @completion_types ||= { :params => [] }
404
+ end
405
+
406
+ def self.completion_type_for(option, opts = {})
407
+ completion_type = opts.delete(:completion)
408
+ completion_type ||= option.completion_type(opts[:format])
409
+ [option.switches].flatten(1).each { |s| completion_types[s] = completion_type }
410
+ end
411
+
355
412
  private
356
413
 
357
414
  def self.inherited_output_definition