hammer_cli 0.19.0 → 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (213) 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/release_notes.md +32 -5
  9. data/lib/hammer_cli.rb +1 -0
  10. data/lib/hammer_cli/abstract.rb +61 -4
  11. data/lib/hammer_cli/apipie/api_connection.rb +5 -1
  12. data/lib/hammer_cli/apipie/command.rb +3 -2
  13. data/lib/hammer_cli/apipie/option_builder.rb +15 -13
  14. data/lib/hammer_cli/apipie/option_definition.rb +9 -7
  15. data/lib/hammer_cli/bash.rb +2 -0
  16. data/lib/hammer_cli/bash/completion.rb +159 -0
  17. data/lib/hammer_cli/bash/prebuild_command.rb +21 -0
  18. data/lib/hammer_cli/command_extensions.rb +21 -1
  19. data/lib/hammer_cli/connection.rb +4 -0
  20. data/lib/hammer_cli/exception_handler.rb +11 -2
  21. data/lib/hammer_cli/full_help.rb +8 -1
  22. data/lib/hammer_cli/help/builder.rb +29 -3
  23. data/lib/hammer_cli/logger_watch.rb +1 -1
  24. data/lib/hammer_cli/main.rb +5 -3
  25. data/lib/hammer_cli/options/normalizers.rb +7 -3
  26. data/lib/hammer_cli/options/option_definition.rb +26 -6
  27. data/lib/hammer_cli/options/option_family.rb +114 -0
  28. data/lib/hammer_cli/options/predefined.rb +1 -1
  29. data/lib/hammer_cli/output.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 +30 -80
  36. data/lib/hammer_cli/output/adapter/yaml.rb +6 -3
  37. data/lib/hammer_cli/output/definition.rb +11 -56
  38. data/lib/hammer_cli/output/generators.rb +1 -0
  39. data/lib/hammer_cli/output/generators/table.rb +121 -0
  40. data/lib/hammer_cli/output/output.rb +2 -4
  41. data/lib/hammer_cli/settings.rb +2 -1
  42. data/lib/hammer_cli/subcommand.rb +25 -1
  43. data/lib/hammer_cli/testing/command_assertions.rb +2 -2
  44. data/lib/hammer_cli/utils.rb +22 -0
  45. data/lib/hammer_cli/version.rb +1 -1
  46. data/locale/ca/LC_MESSAGES/hammer-cli.mo +0 -0
  47. data/locale/de/LC_MESSAGES/hammer-cli.mo +0 -0
  48. data/locale/en/LC_MESSAGES/hammer-cli.mo +0 -0
  49. data/locale/en_GB/LC_MESSAGES/hammer-cli.mo +0 -0
  50. data/locale/es/LC_MESSAGES/hammer-cli.mo +0 -0
  51. data/locale/fr/LC_MESSAGES/hammer-cli.mo +0 -0
  52. data/locale/it/LC_MESSAGES/hammer-cli.mo +0 -0
  53. data/locale/ja/LC_MESSAGES/hammer-cli.mo +0 -0
  54. data/locale/ko/LC_MESSAGES/hammer-cli.mo +0 -0
  55. data/locale/pt_BR/LC_MESSAGES/hammer-cli.mo +0 -0
  56. data/locale/ru/LC_MESSAGES/hammer-cli.mo +0 -0
  57. data/locale/zh_CN/LC_MESSAGES/hammer-cli.mo +0 -0
  58. data/locale/zh_TW/LC_MESSAGES/hammer-cli.mo +0 -0
  59. data/man/hammer.1.gz +0 -0
  60. data/test/unit/abstract_test.rb +23 -2
  61. data/test/unit/apipie/api_connection_test.rb +1 -0
  62. data/test/unit/apipie/option_builder_test.rb +8 -0
  63. data/test/unit/bash_test.rb +138 -0
  64. data/test/unit/command_extensions_test.rb +67 -49
  65. data/test/unit/exception_handler_test.rb +44 -0
  66. data/test/unit/help/builder_test.rb +22 -0
  67. data/test/unit/options/option_family_test.rb +48 -0
  68. data/test/unit/output/adapter/base_test.rb +58 -0
  69. data/test/unit/output/adapter/csv_test.rb +63 -1
  70. data/test/unit/output/adapter/json_test.rb +61 -0
  71. data/test/unit/output/adapter/table_test.rb +70 -1
  72. data/test/unit/output/adapter/yaml_test.rb +59 -0
  73. data/test/unit/output/definition_test.rb +7 -7
  74. data/test/unit/output/output_test.rb +3 -3
  75. metadata +83 -345
  76. data/hammer_cli_complete +0 -13
  77. data/test/reports/TEST-Fields-ContainerField-display-.xml +0 -7
  78. data/test/reports/TEST-Fields-ContainerField-display-blank-is-allowed.xml +0 -15
  79. data/test/reports/TEST-Fields-ContainerField-display-blank-is-not-allowed.xml +0 -15
  80. data/test/reports/TEST-Fields-ContainerField.xml +0 -7
  81. data/test/reports/TEST-Fields-Field-display-.xml +0 -7
  82. data/test/reports/TEST-Fields-Field-display-blank-is-allowed.xml +0 -11
  83. data/test/reports/TEST-Fields-Field-display-blank-is-not-allowed.xml +0 -11
  84. data/test/reports/TEST-Fields-Field-hide-blank-.xml +0 -11
  85. data/test/reports/TEST-Fields-Field-parameters.xml +0 -9
  86. data/test/reports/TEST-Fields-Field.xml +0 -13
  87. data/test/reports/TEST-HammerCLI-AbstractCommand-build-options.xml +0 -15
  88. data/test/reports/TEST-HammerCLI-AbstractCommand-exception-handler.xml +0 -13
  89. data/test/reports/TEST-HammerCLI-AbstractCommand-logging.xml +0 -21
  90. data/test/reports/TEST-HammerCLI-AbstractCommand-option-builder.xml +0 -11
  91. data/test/reports/TEST-HammerCLI-AbstractCommand-options.xml +0 -11
  92. data/test/reports/TEST-HammerCLI-AbstractCommand-output.xml +0 -19
  93. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-remove-subcommand.xml +0 -11
  94. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-subcommand-.xml +0 -13
  95. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior-subcommand.xml +0 -11
  96. data/test/reports/TEST-HammerCLI-AbstractCommand-subcommand-behavior.xml +0 -7
  97. data/test/reports/TEST-HammerCLI-AbstractCommand.xml +0 -11
  98. data/test/reports/TEST-HammerCLI-Apipie-Command-options.xml +0 -11
  99. data/test/reports/TEST-HammerCLI-Apipie-Command-resource-defined.xml +0 -9
  100. data/test/reports/TEST-HammerCLI-Apipie-Command-setting-resources.xml +0 -19
  101. data/test/reports/TEST-HammerCLI-Apipie-Command.xml +0 -9
  102. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-aliasing-resources.xml +0 -13
  103. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-filtering-options.xml +0 -15
  104. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-required-options.xml +0 -11
  105. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-setting-correct-normalizers.xml +0 -9
  106. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-with-hash-params.xml +0 -11
  107. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder-with-one-simple-param.xml +0 -15
  108. data/test/reports/TEST-HammerCLI-Apipie-OptionBuilder.xml +0 -7
  109. data/test/reports/TEST-HammerCLI-Completer-command-completion.xml +0 -29
  110. data/test/reports/TEST-HammerCLI-Completer-option-value-completion.xml +0 -17
  111. data/test/reports/TEST-HammerCLI-Completer-subcommand-completion.xml +0 -19
  112. data/test/reports/TEST-HammerCLI-Completer.xml +0 -7
  113. data/test/reports/TEST-HammerCLI-CompleterLine-line-complete.xml +0 -25
  114. data/test/reports/TEST-HammerCLI-CompleterLine-splitting-words.xml +0 -29
  115. data/test/reports/TEST-HammerCLI-CompleterLine.xml +0 -7
  116. data/test/reports/TEST-HammerCLI-CompleterWord-complete-.xml +0 -23
  117. data/test/reports/TEST-HammerCLI-CompleterWord-quote.xml +0 -15
  118. data/test/reports/TEST-HammerCLI-CompleterWord-quoted-.xml +0 -13
  119. data/test/reports/TEST-HammerCLI-CompleterWord.xml +0 -7
  120. data/test/reports/TEST-HammerCLI-Connection.xml +0 -21
  121. data/test/reports/TEST-HammerCLI-ExceptionHandler.xml +0 -21
  122. data/test/reports/TEST-HammerCLI-I18n.xml +0 -11
  123. data/test/reports/TEST-HammerCLI-MainCommand-loading-context-password.xml +0 -11
  124. data/test/reports/TEST-HammerCLI-MainCommand-loading-context-username.xml +0 -11
  125. data/test/reports/TEST-HammerCLI-MainCommand-loading-context-verbose.xml +0 -9
  126. data/test/reports/TEST-HammerCLI-MainCommand-loading-context.xml +0 -7
  127. data/test/reports/TEST-HammerCLI-MainCommand.xml +0 -7
  128. data/test/reports/TEST-HammerCLI-Modules-find-by-name.xml +0 -13
  129. data/test/reports/TEST-HammerCLI-Modules-load-a-module-module-not-found.xml +0 -13
  130. data/test/reports/TEST-HammerCLI-Modules-load-a-module-module-runtime-exception.xml +0 -13
  131. data/test/reports/TEST-HammerCLI-Modules-load-a-module-success.xml +0 -15
  132. data/test/reports/TEST-HammerCLI-Modules-load-a-module.xml +0 -7
  133. data/test/reports/TEST-HammerCLI-Modules-load-all-modules.xml +0 -9
  134. data/test/reports/TEST-HammerCLI-Modules-names.xml +0 -13
  135. data/test/reports/TEST-HammerCLI-Modules.xml +0 -7
  136. data/test/reports/TEST-HammerCLI-OptionBuilderContainer.0.xml +0 -7
  137. data/test/reports/TEST-HammerCLI-OptionBuilderContainer.xml +0 -11
  138. data/test/reports/TEST-HammerCLI-Options-Normalizers-abstract.xml +0 -9
  139. data/test/reports/TEST-HammerCLI-Options-Normalizers-bool.xml +0 -31
  140. data/test/reports/TEST-HammerCLI-Options-Normalizers-datetime.xml +0 -17
  141. data/test/reports/TEST-HammerCLI-Options-Normalizers-enum.xml +0 -15
  142. data/test/reports/TEST-HammerCLI-Options-Normalizers-enumlist.xml +0 -21
  143. data/test/reports/TEST-HammerCLI-Options-Normalizers-json-input.xml +0 -15
  144. data/test/reports/TEST-HammerCLI-Options-Normalizers-key-value-list.xml +0 -17
  145. data/test/reports/TEST-HammerCLI-Options-Normalizers-list.xml +0 -15
  146. data/test/reports/TEST-HammerCLI-Options-Normalizers.xml +0 -7
  147. data/test/reports/TEST-HammerCLI-Options-OptionDefinition-context.xml +0 -9
  148. data/test/reports/TEST-HammerCLI-Options-OptionDefinition-formatters.xml +0 -11
  149. data/test/reports/TEST-HammerCLI-Options-OptionDefinition.xml +0 -7
  150. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-error-messages.xml +0 -15
  151. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-messages.xml +0 -11
  152. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract-test-data-for-field.xml +0 -15
  153. data/test/reports/TEST-HammerCLI-Output-Adapter-Abstract.xml +0 -17
  154. data/test/reports/TEST-HammerCLI-Output-Adapter-Base-print-collection-show-ids.xml +0 -9
  155. data/test/reports/TEST-HammerCLI-Output-Adapter-Base-print-collection.xml +0 -27
  156. data/test/reports/TEST-HammerCLI-Output-Adapter-Base.xml +0 -7
  157. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-formatters.xml +0 -11
  158. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-fields-with-collections.xml +0 -13
  159. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-fields-with-containers.xml +0 -11
  160. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection-handle-ids.xml +0 -11
  161. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-collection.xml +0 -11
  162. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues-print-message.xml +0 -11
  163. data/test/reports/TEST-HammerCLI-Output-Adapter-CSValues.xml +0 -7
  164. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-column-width.xml +0 -15
  165. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-formatters.xml +0 -11
  166. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-handle-ids.xml +0 -11
  167. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection-sort-columns.xml +0 -9
  168. data/test/reports/TEST-HammerCLI-Output-Adapter-Table-print-collection.xml +0 -11
  169. data/test/reports/TEST-HammerCLI-Output-Adapter-Table.xml +0 -7
  170. data/test/reports/TEST-HammerCLI-Output-Definition-empty-.xml +0 -11
  171. data/test/reports/TEST-HammerCLI-Output-Definition.xml +0 -11
  172. data/test/reports/TEST-HammerCLI-Output-Dsl-collection.xml +0 -13
  173. data/test/reports/TEST-HammerCLI-Output-Dsl-custom-fields.xml +0 -11
  174. data/test/reports/TEST-HammerCLI-Output-Dsl-fields.xml +0 -15
  175. data/test/reports/TEST-HammerCLI-Output-Dsl-label.xml +0 -13
  176. data/test/reports/TEST-HammerCLI-Output-Dsl-path-definition.xml +0 -13
  177. data/test/reports/TEST-HammerCLI-Output-Dsl.xml +0 -9
  178. data/test/reports/TEST-HammerCLI-Output-FieldFilter.xml +0 -13
  179. data/test/reports/TEST-HammerCLI-Output-Formatters-BooleanFormatter.xml +0 -11
  180. data/test/reports/TEST-HammerCLI-Output-Formatters-ColorFormatter.xml +0 -9
  181. data/test/reports/TEST-HammerCLI-Output-Formatters-DateFormatter.xml +0 -11
  182. data/test/reports/TEST-HammerCLI-Output-Formatters-FieldFormatter.xml +0 -13
  183. data/test/reports/TEST-HammerCLI-Output-Formatters-FormatterContainer.xml +0 -13
  184. data/test/reports/TEST-HammerCLI-Output-Formatters-FormatterLibrary.xml +0 -11
  185. data/test/reports/TEST-HammerCLI-Output-Formatters-KeyValueFormatter.xml +0 -13
  186. data/test/reports/TEST-HammerCLI-Output-Formatters-ListFormatter.xml +0 -13
  187. data/test/reports/TEST-HammerCLI-Output-Formatters-LongTextFormatter.xml +0 -13
  188. data/test/reports/TEST-HammerCLI-Output-Output-adapters.xml +0 -17
  189. data/test/reports/TEST-HammerCLI-Output-Output-data.xml +0 -15
  190. data/test/reports/TEST-HammerCLI-Output-Output-formatters.xml +0 -9
  191. data/test/reports/TEST-HammerCLI-Output-Output-messages.xml +0 -19
  192. data/test/reports/TEST-HammerCLI-Output-Output.xml +0 -7
  193. data/test/reports/TEST-HammerCLI-Output-RecordCollection.xml +0 -13
  194. data/test/reports/TEST-HammerCLI-Settings-load-from-paths.xml +0 -15
  195. data/test/reports/TEST-HammerCLI-Settings.xml +0 -25
  196. data/test/reports/TEST-HammerCLI-ShellHistory-loading-old-history.xml +0 -11
  197. data/test/reports/TEST-HammerCLI-ShellHistory-saving-history.xml +0 -15
  198. data/test/reports/TEST-HammerCLI-ShellHistory.xml +0 -7
  199. data/test/reports/TEST-MiniTest-Spec.xml +0 -7
  200. data/test/reports/TEST-String-camelize.xml +0 -11
  201. data/test/reports/TEST-String-formatting.xml +0 -17
  202. data/test/reports/TEST-String-indent.xml +0 -11
  203. data/test/reports/TEST-String-interactive-.xml +0 -13
  204. data/test/reports/TEST-String.xml +0 -7
  205. data/test/reports/TEST-constraints-HammerCLI-Validator-AllConstraint-exist-.xml +0 -13
  206. data/test/reports/TEST-constraints-HammerCLI-Validator-AllConstraint.xml +0 -7
  207. data/test/reports/TEST-constraints-HammerCLI-Validator-AnyConstraint-exist-.xml +0 -13
  208. data/test/reports/TEST-constraints-HammerCLI-Validator-AnyConstraint.xml +0 -7
  209. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-exist-.xml +0 -9
  210. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-rejected.xml +0 -13
  211. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint-required.xml +0 -13
  212. data/test/reports/TEST-constraints-HammerCLI-Validator-BaseConstraint.xml +0 -7
  213. data/test/reports/TEST-constraints.xml +0 -7
@@ -65,8 +65,8 @@ module HammerCLI::Apipie
65
65
  method_options(options)
66
66
  end
67
67
 
68
- def print_data(data)
69
- print_collection(output_definition, data) unless output_definition.empty?
68
+ def print_data(data, options = {})
69
+ print_collection(output_definition, data, options) unless output_definition.empty?
70
70
  print_success_message(data) unless success_message.nil?
71
71
  end
72
72
 
@@ -86,6 +86,7 @@ module HammerCLI::Apipie
86
86
  declared_options << option
87
87
  block ||= option.default_conversion_block
88
88
  define_accessors_for(option, &block)
89
+ completion_type_for(option, opts)
89
90
  end
90
91
  extend_options_help(option) if option.value_formatter.is_a?(HammerCLI::Options::Normalizers::ListNested)
91
92
  option
@@ -41,12 +41,11 @@ module HammerCLI::Apipie
41
41
  end
42
42
 
43
43
  def create_option(param, resource_name_map)
44
- option(
45
- option_switch(param, resource_name_map),
46
- option_type(param, resource_name_map),
47
- option_desc(param),
48
- option_opts(param)
49
- )
44
+ family = HammerCLI::Options::OptionFamily.new
45
+ family.parent(option_switch(param, resource_name_map),
46
+ option_type(param, resource_name_map),
47
+ option_desc(param),
48
+ option_opts(param, resource_name_map))
50
49
  end
51
50
 
52
51
  def option_switch(param, resource_name_map)
@@ -61,7 +60,7 @@ module HammerCLI::Apipie
61
60
  param.description || " "
62
61
  end
63
62
 
64
- def option_opts(param)
63
+ def option_opts(param, resource_name_map)
65
64
  opts = {}
66
65
  opts[:required] = true if (param.required? and require_options?)
67
66
  if param.expected_type.to_s == 'array'
@@ -80,19 +79,22 @@ module HammerCLI::Apipie
80
79
  end
81
80
  opts[:attribute_name] = HammerCLI.option_accessor_name(param.name)
82
81
  opts[:referenced_resource] = resource_name(param)
82
+ opts[:aliased_resource] = aliased_name(resource_name(param), resource_name_map)
83
83
 
84
84
  return opts
85
85
  end
86
86
 
87
+ def aliased_name(name, resource_name_map)
88
+ return if name.nil?
89
+
90
+ resource_name_map[name.to_s] || resource_name_map[name.to_sym] || name
91
+ end
92
+
87
93
  def aliased(param, resource_name_map)
88
94
  resource_name = resource_name(param)
95
+ return param.name if resource_name.nil?
89
96
 
90
- if resource_name.nil?
91
- return param.name
92
- else
93
- aliased_name = resource_name_map[resource_name.to_s] || resource_name_map[resource_name.to_sym] || resource_name
94
- return param.name.gsub(resource_name, aliased_name.to_s)
95
- end
97
+ param.name.gsub(resource_name, aliased_name(resource_name, resource_name_map).to_s)
96
98
  end
97
99
 
98
100
  def resource_name(param)
@@ -1,21 +1,23 @@
1
1
  require File.join(File.dirname(__FILE__), 'options')
2
2
 
3
3
  module HammerCLI::Apipie
4
-
5
4
  class OptionDefinition < HammerCLI::Options::OptionDefinition
6
-
7
- attr_accessor :referenced_resource
5
+ attr_accessor :referenced_resource, :aliased_resource, :family
8
6
 
9
7
  def initialize(switches, type, description, options = {})
10
- if options.has_key? :referenced_resource
11
- self.referenced_resource = options.delete(:referenced_resource).to_s if options[:referenced_resource]
12
- end
8
+ @referenced_resource = options[:referenced_resource].to_s if options[:referenced_resource]
9
+ @aliased_resource = options[:aliased_resource].to_s if options[:aliased_resource]
10
+ @family = options[:family]
13
11
  super
14
12
  # Apipie currently sends descriptions as escaped HTML once this is changed this should be removed.
15
13
  # See #15198 on Redmine.
16
14
  @description = CGI::unescapeHTML(description)
17
15
  end
18
16
 
19
- end
17
+ def child?
18
+ return unless @family
20
19
 
20
+ @family.children.include?(self)
21
+ end
22
+ end
21
23
  end
@@ -0,0 +1,2 @@
1
+ require 'hammer_cli/bash/prebuild_command'
2
+ require 'hammer_cli/bash/completion'
@@ -0,0 +1,159 @@
1
+ require 'json'
2
+
3
+ module HammerCLI
4
+ module Bash
5
+ class Completion
6
+ def initialize(dict)
7
+ @dict = dict
8
+ end
9
+
10
+ def complete(line)
11
+ @complete_line = line.end_with?(' ')
12
+ full_path = line.split(' ')
13
+ complete_path = @complete_line ? full_path : full_path[0..-2]
14
+ dict, path = traverse_tree(@dict, complete_path)
15
+
16
+ return [] unless path.empty? # lost during traversing
17
+
18
+ partial = @complete_line ? '' : full_path.last
19
+ finish_word(dict, partial)
20
+ end
21
+
22
+ def self.load_description(path)
23
+ JSON.load(File.open(path))
24
+ rescue Errno::ENOENT
25
+ {}
26
+ end
27
+
28
+ private
29
+
30
+ def finish_word(dict, incomplete)
31
+ finish_option_value(dict, incomplete) ||
32
+ (finish_option_or_subcommand(dict, incomplete) + finish_param(dict, incomplete))
33
+ end
34
+
35
+ def finish_option_or_subcommand(dict, incomplete)
36
+ dict.keys.select { |k| k.is_a?(String) && k =~ /^#{incomplete}/ }.map { |k| k + ' ' }
37
+ end
38
+
39
+ def complete_value(value_description, partial, is_param)
40
+ case value_description['type']
41
+ when 'value'
42
+ if !partial.empty?
43
+ []
44
+ elsif is_param
45
+ ['--->', 'Add parameter']
46
+ else
47
+ ['--->', 'Add option <value>']
48
+ end
49
+ when 'directory'
50
+ directories(partial)
51
+ when 'file'
52
+ files(partial, value_description)
53
+ when 'enum'
54
+ enum(partial, value_description['values'])
55
+ when 'multienum'
56
+ multienum(partial, value_description['values'])
57
+ when 'schema'
58
+ schema(value_description['schema'])
59
+ when 'list'
60
+ ['--->', 'Add comma-separated list of values']
61
+ when 'key_value_list'
62
+ ['--->', 'Add comma-separated list of key=value']
63
+ end
64
+ end
65
+
66
+ def finish_param(dict, incomplete)
67
+ if dict['params'] && !dict['params'].empty?
68
+ complete_value(dict['params'].first, incomplete, true)
69
+ else
70
+ []
71
+ end
72
+ end
73
+
74
+ def finish_option_value(dict, incomplete)
75
+ complete_value(dict, incomplete, false) if dict.key?('type')
76
+ end
77
+
78
+ def traverse_tree(dict, path)
79
+ return [dict, []] if path.nil? || path.empty?
80
+ result = if dict.key?(path.first)
81
+ if path.first.start_with?('-')
82
+ parse_option(dict, path)
83
+ else
84
+ parse_subcommand(dict, path)
85
+ end
86
+ elsif dict['params']
87
+ # traverse params one by one
88
+ parse_params(dict, path)
89
+ else
90
+ # not found
91
+ [{}, path]
92
+ end
93
+ result
94
+ end
95
+
96
+ def parse_params(dict, path)
97
+ traverse_tree({ 'params' => dict['params'][1..-1] }, path[1..-1])
98
+ end
99
+
100
+ def parse_subcommand(dict, path)
101
+ traverse_tree(dict[path.first], path[1..-1])
102
+ end
103
+
104
+ def parse_option(dict, path)
105
+ if dict[path.first]['type'] == 'flag' # flag
106
+ traverse_tree(dict, path[1..-1])
107
+ elsif path.length >= 2 # option with value
108
+ traverse_tree(dict, path[2..-1])
109
+ else # option with value missing
110
+ [dict[path.first], path[1..-1]]
111
+ end
112
+ end
113
+
114
+ def directories(partial = '')
115
+ dirs = []
116
+ dirs += Dir.glob("#{partial}*").select { |f| File.directory?(f) }
117
+ dirs = dirs.map { |d| d + '/' } if dirs.length == 1
118
+ dirs
119
+ end
120
+
121
+ def files(partial = '', opts = {})
122
+ filter = opts.fetch('filter', '.*')
123
+ file_names = []
124
+ file_names += Dir.glob("#{partial}*").select do |f|
125
+ File.directory?(f) || f =~ /#{filter}/
126
+ end
127
+ file_names.map { |f| File.directory?(f) ? f + '/' : f + ' ' }
128
+ end
129
+
130
+ def enum(partial = '', values = [])
131
+ values.select { |v| v.start_with?(partial) }.map { |v| v + ' ' }
132
+ end
133
+
134
+ def multienum(partial = '', values = [])
135
+ return values if partial.empty?
136
+
137
+ parts = partial.split(',')
138
+ resolved = []
139
+ to_complete = parts.each_with_object([]) do |part, res|
140
+ next resolved << part if values.include?(part)
141
+
142
+ res << part
143
+ end
144
+
145
+ hints = to_complete.map do |p|
146
+ values.select { |v| v.start_with?(p) }
147
+ end.flatten(1).uniq
148
+ return values - parts if hints.empty?
149
+ return [(resolved + hints).join(',')] if hints.size == 1
150
+
151
+ hints
152
+ end
153
+
154
+ def schema(template = '')
155
+ ['--->', "Add value by following schema: #{template}"]
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,21 @@
1
+ module HammerCLI
2
+ module Bash
3
+ class PrebuildCompletionCommand < HammerCLI::AbstractCommand
4
+ def execute
5
+ map = HammerCLI::MainCommand.completion_map
6
+ cache_file = HammerCLI::Settings.get(:completion_cache_file)
7
+ cache_dir = File.dirname(cache_file)
8
+ FileUtils.mkdir_p(cache_dir) unless File.directory?(cache_dir)
9
+ File.write(File.expand_path(cache_file), map.to_json)
10
+
11
+ HammerCLI::EX_OK
12
+ end
13
+ end
14
+ end
15
+
16
+ HammerCLI::MainCommand.subcommand(
17
+ 'prebuild-bash-completion',
18
+ _('Prepare map of options and subcommands for Bash completion'),
19
+ HammerCLI::Bash::PrebuildCompletionCommand
20
+ )
21
+ end
@@ -15,7 +15,7 @@ module HammerCLI
15
15
  ALLOWED_EXTENSIONS = %i[
16
16
  option command_options before_print data output help request
17
17
  request_headers headers request_options options request_params params
18
- option_sources predefined_options use_option
18
+ option_sources predefined_options use_option option_family
19
19
  ].freeze
20
20
 
21
21
  def initialize(options = {})
@@ -86,6 +86,11 @@ module HammerCLI
86
86
  @option_sources_block = block
87
87
  end
88
88
 
89
+ def self.option_family(options = {}, &block)
90
+ @option_family_opts = options
91
+ @option_family_block = block
92
+ end
93
+
89
94
  # Object
90
95
 
91
96
  def extend_options(command_class)
@@ -151,6 +156,13 @@ module HammerCLI
151
156
  self.class.extend_option_sources(sources, command)
152
157
  end
153
158
 
159
+ def extend_option_family(command_class)
160
+ allowed = @only & %i[option_family]
161
+ return if allowed.empty? || (allowed & @except).any?
162
+
163
+ self.class.extend_option_family(command_class)
164
+ end
165
+
154
166
  def delegatee(command_class)
155
167
  self.class.delegatee = command_class
156
168
  end
@@ -234,5 +246,13 @@ module HammerCLI
234
246
  @option_sources_block.call(sources, command)
235
247
  logger.debug("Called block for #{@delegatee} option sources:\n\t#{@option_sources_block}")
236
248
  end
249
+
250
+ def self.extend_option_family(command_class)
251
+ return if @option_family_block.nil?
252
+
253
+ @option_family_opts[:creator] = command_class
254
+ command_class.send(:option_family, @option_family_opts, &@option_family_block)
255
+ logger.debug("Called option family block for #{command_class}:\n\t#{@option_family_block}")
256
+ end
237
257
  end
238
258
  end
@@ -35,6 +35,10 @@ module HammerCLI
35
35
  connections[name]
36
36
  end
37
37
 
38
+ def available
39
+ connections.select { |k, v| !v.nil? }.values.first
40
+ end
41
+
38
42
  private
39
43
 
40
44
  def connections
@@ -69,7 +69,7 @@ module HammerCLI
69
69
 
70
70
  def handle_usage_exception(e)
71
71
  print_error (_("Error: %{message}") + "\n\n" +
72
- _("See: '%{path} --help'.")) % {:message => e.message, :path => e.command.invocation_path}
72
+ _("See: '%{path} --help'.")) % { message: e.message, path: HammerCLI.expand_invocation_path(e.command.invocation_path) }
73
73
  log_full_error e
74
74
  HammerCLI::EX_USAGE
75
75
  end
@@ -138,7 +138,16 @@ module HammerCLI
138
138
  end
139
139
 
140
140
  def handle_apipie_missing_arguments_error(e)
141
- message = _("Missing arguments for %s") % "'#{e.params.join("', '")}'"
141
+ params = e.params.map do |p|
142
+ param = p[/\[.+\]/]
143
+ param = if param.nil?
144
+ p.tr('_', '-')
145
+ else
146
+ p.scan(/\[[^\[\]]+\]/).first[1...-1].tr('_', '-')
147
+ end
148
+ "--#{param}"
149
+ end
150
+ message = _("Missing arguments for %s.") % "'#{params.uniq.join("', '")}'"
142
151
  print_error message
143
152
  log_full_error e, message
144
153
  HammerCLI::EX_USAGE
@@ -6,8 +6,11 @@ module HammerCLI
6
6
 
7
7
  def execute
8
8
  @adapter = option_md? ? MDAdapter.new : TxtAdapter.new
9
+ HammerCLI.context[:full_help] = true
10
+ @invocation_paths = {}
9
11
  print_heading
10
12
  print_help
13
+ HammerCLI.context[:full_help] = false
11
14
  HammerCLI::EX_OK
12
15
  end
13
16
 
@@ -19,9 +22,13 @@ module HammerCLI
19
22
  end
20
23
 
21
24
  def print_help(name='hammer', command=HammerCLI::MainCommand, desc='')
22
- @adapter.print_command(name, desc, command.new(name).help)
25
+ @invocation_paths[name] ||= []
26
+ @adapter.print_command(name, desc, command.new(name, path: @invocation_paths[name]).help)
23
27
 
24
28
  command.recognised_subcommands.each do |sub_cmd|
29
+ path = "#{name} #{sub_cmd.names.first}"
30
+ @invocation_paths[path] ||= []
31
+ @invocation_paths[path] += @invocation_paths[name]
25
32
  print_help(@adapter.command_name(name, sub_cmd.names.first), sub_cmd.subcommand_class, sub_cmd.description)
26
33
  end
27
34
  end
@@ -14,7 +14,7 @@ module HammerCLI
14
14
  def add_usage(invocation_path, usage_descriptions)
15
15
  heading(Clamp.message(:usage_heading))
16
16
  usage_descriptions.each do |usage|
17
- puts " #{invocation_path} #{usage}".rstrip
17
+ puts " #{HammerCLI.expand_invocation_path(invocation_path)} #{usage}".rstrip
18
18
  end
19
19
  end
20
20
 
@@ -29,12 +29,19 @@ module HammerCLI
29
29
 
30
30
  label_width = DEFAULT_LABEL_INDENT
31
31
  items.each do |item|
32
- label, description = item.help
32
+ label = item.help.first
33
33
  label_width = label.size if label.size > label_width
34
34
  end
35
35
 
36
36
  items.each do |item|
37
- label, description = item.help
37
+ if item.respond_to?(:child?) && item.child?
38
+ next unless HammerCLI.context[:full_help]
39
+ end
40
+ label, description = if !HammerCLI.context[:full_help] && item.respond_to?(:family) && item.family
41
+ [item.family.switch, item.family.description || item.help[1]]
42
+ else
43
+ item.help
44
+ end
38
45
  description.gsub(/^(.)/) { Unicode::capitalize($1) }.each_line do |line|
39
46
  puts " %-#{label_width}s %s" % [label, line]
40
47
  label = ''
@@ -54,6 +61,25 @@ module HammerCLI
54
61
  label = HighLine.color(label, :bold) if @richtext
55
62
  puts label
56
63
  end
64
+
65
+ private
66
+
67
+ def expand_invocation_path(path)
68
+ bits = path.split(' ')
69
+ parent_command = HammerCLI::MainCommand
70
+ new_path = (bits[1..-1] || []).each_with_object([]) do |bit, names|
71
+ subcommand = parent_command.find_subcommand(bit)
72
+ next if subcommand.nil?
73
+
74
+ names << if subcommand.names.size > 1
75
+ "<#{subcommand.names.join('|')}>"
76
+ else
77
+ subcommand.names.first
78
+ end
79
+ parent_command = subcommand.subcommand_class
80
+ end
81
+ new_path.unshift(bits.first).join(' ')
82
+ end
57
83
  end
58
84
  end
59
85
  end