hammer_cli 0.8.0 → 0.9.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 (80) hide show
  1. checksums.yaml +4 -4
  2. data/config/cli_config.template.yml +2 -2
  3. data/doc/release_notes.md +15 -0
  4. data/lib/hammer_cli/abstract.rb +22 -31
  5. data/lib/hammer_cli/apipie.rb +1 -0
  6. data/lib/hammer_cli/apipie/api_connection.rb +27 -0
  7. data/lib/hammer_cli/apipie/option_builder.rb +3 -3
  8. data/lib/hammer_cli/apipie/resource.rb +1 -26
  9. data/lib/hammer_cli/connection.rb +12 -11
  10. data/lib/hammer_cli/context.rb +4 -2
  11. data/lib/hammer_cli/exception_handler.rb +1 -1
  12. data/lib/hammer_cli/help/builder.rb +58 -0
  13. data/lib/hammer_cli/help/text_builder.rb +79 -0
  14. data/lib/hammer_cli/logger.rb +24 -21
  15. data/lib/hammer_cli/options/normalizers.rb +13 -2
  16. data/lib/hammer_cli/output/adapter/table.rb +2 -0
  17. data/lib/hammer_cli/output/formatters.rb +1 -1
  18. data/lib/hammer_cli/output/utils.rb +43 -0
  19. data/lib/hammer_cli/table_print/column.rb +19 -0
  20. data/lib/hammer_cli/table_print/formatter.rb +18 -0
  21. data/lib/hammer_cli/utils.rb +5 -1
  22. data/lib/hammer_cli/validator.rb +12 -2
  23. data/lib/hammer_cli/version.rb +1 -1
  24. data/locale/ca/LC_MESSAGES/hammer-cli.mo +0 -0
  25. data/locale/ca/hammer-cli.edit.po +26 -15
  26. data/locale/ca/hammer-cli.po +22 -6
  27. data/locale/de/LC_MESSAGES/hammer-cli.mo +0 -0
  28. data/locale/de/hammer-cli.edit.po +32 -20
  29. data/locale/de/hammer-cli.po +22 -6
  30. data/locale/en/LC_MESSAGES/hammer-cli.mo +0 -0
  31. data/locale/en/hammer-cli.edit.po +47 -29
  32. data/locale/en/hammer-cli.po +21 -5
  33. data/locale/en_GB/LC_MESSAGES/hammer-cli.mo +0 -0
  34. data/locale/en_GB/hammer-cli.edit.po +28 -17
  35. data/locale/en_GB/hammer-cli.po +22 -6
  36. data/locale/es/LC_MESSAGES/hammer-cli.mo +0 -0
  37. data/locale/es/hammer-cli.edit.po +28 -17
  38. data/locale/es/hammer-cli.po +22 -6
  39. data/locale/fr/LC_MESSAGES/hammer-cli.mo +0 -0
  40. data/locale/fr/hammer-cli.edit.po +28 -17
  41. data/locale/fr/hammer-cli.po +22 -6
  42. data/locale/hammer-cli.pot +49 -31
  43. data/locale/it/LC_MESSAGES/hammer-cli.mo +0 -0
  44. data/locale/it/hammer-cli.edit.po +23 -12
  45. data/locale/it/hammer-cli.po +22 -6
  46. data/locale/ja/LC_MESSAGES/hammer-cli.mo +0 -0
  47. data/locale/ja/hammer-cli.edit.po +28 -17
  48. data/locale/ja/hammer-cli.po +22 -6
  49. data/locale/ko/LC_MESSAGES/hammer-cli.mo +0 -0
  50. data/locale/ko/hammer-cli.edit.po +27 -16
  51. data/locale/ko/hammer-cli.po +22 -6
  52. data/locale/pt_BR/LC_MESSAGES/hammer-cli.mo +0 -0
  53. data/locale/pt_BR/hammer-cli.edit.po +30 -19
  54. data/locale/pt_BR/hammer-cli.po +22 -6
  55. data/locale/ru/LC_MESSAGES/hammer-cli.mo +0 -0
  56. data/locale/ru/hammer-cli.edit.po +28 -17
  57. data/locale/ru/hammer-cli.po +22 -6
  58. data/locale/zh_CN/LC_MESSAGES/hammer-cli.mo +0 -0
  59. data/locale/zh_CN/hammer-cli.edit.po +28 -17
  60. data/locale/zh_CN/hammer-cli.po +22 -6
  61. data/locale/zh_TW/LC_MESSAGES/hammer-cli.mo +0 -0
  62. data/locale/zh_TW/hammer-cli.edit.po +27 -16
  63. data/locale/zh_TW/hammer-cli.po +22 -6
  64. data/man/hammer.1.gz +0 -0
  65. data/test/functional/help_test.rb +87 -0
  66. data/test/test_helper.rb +6 -0
  67. data/test/unit/abstract_test.rb +9 -0
  68. data/test/unit/apipie/api_connection_test.rb +38 -0
  69. data/test/unit/apipie/command_test.rb +6 -46
  70. data/test/unit/connection_test.rb +45 -54
  71. data/test/unit/exception_handler_test.rb +1 -1
  72. data/test/unit/fixtures/apipie/documented.json +1 -1
  73. data/test/unit/help/builder_test.rb +57 -0
  74. data/test/unit/help/text_builder_test.rb +140 -0
  75. data/test/unit/logger_test.rb +19 -0
  76. data/test/unit/options/normalizers_test.rb +12 -0
  77. data/test/unit/output/adapter/table_test.rb +101 -13
  78. data/test/unit/output/formatters_test.rb +6 -3
  79. data/test/unit/validator_test.rb +31 -2
  80. metadata +207 -179
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2dc560a54a8356574b61f94171e0f2f3eaba55be
4
- data.tar.gz: baecee7550c67ddd53dd4fb41a75e8b917b7f430
3
+ metadata.gz: 9c28ad069fcd115c4b6f01ad2b5d0b2cdf8b3cbd
4
+ data.tar.gz: 2f9a543685a78f837bd1d1b657702c745c2ae0ba
5
5
  SHA512:
6
- metadata.gz: a442abbc69a621586676c5a12999856bd1a470e15832f03cc5b5d59e1b7e9e12dd714b1e91faff6534222e68babd344ff340d392fbe4f01879431d1bd13fce4c
7
- data.tar.gz: 812bc9348b53072052e49e5384dcbcacb46ce9553cf3bfd71dfa19a1aaeb276f9d3bed21d337f5bbdcb33951b14822664643ae9e2eabf6340289fad88336d283
6
+ metadata.gz: e641575e3077ce1a854ba6f6e7bfc96d9b03c634a56ee09dcb8d5d486db188aa2bd5f4e7856dcc4f30c08b9ab6630d73397e3a9726db833064d11fc8afdfeecb
7
+ data.tar.gz: 287e3b3f607305f302ff58d6c74c6cc871b46d627fd32e0392a2443a2f516561934344419ab9333f3083804a15996c4d9f4695b0eeb32357b8fb022416fdb2e3
@@ -6,6 +6,8 @@
6
6
  # :per_page: 20
7
7
  # Location of shell history file
8
8
  :history_file: '~/.hammer/history'
9
+ # Mark translated strings with X characters (for developers)
10
+ #:mark_translated: false
9
11
 
10
12
 
11
13
  # Enable/disable color output of logger in Clamp commands
@@ -29,5 +31,3 @@
29
31
  # Log record pattern (logging gem syntax)
30
32
  #:log_pattern: '[%5l %d %c] %m'
31
33
 
32
- # Mark translated strings with X characters (for developers)
33
- #:mark_translated: false
data/doc/release_notes.md CHANGED
@@ -1,6 +1,21 @@
1
1
  Release notes
2
2
  =============
3
3
 
4
+ ### 0.9.0 (2016-12-15)
5
+ * Double quotes in list type params ([#17180](http://projects.theforeman.org/issues/17180))
6
+ * API connection moved to context ([PR #227](https://github.com/theforeman/hammer-cli/pull/227)) ([#8016](http://projects.theforeman.org/issues/8016))
7
+ * Log related error messages to stderr ([#17508](http://projects.theforeman.org/issues/17508))
8
+ * Respect special chars width ([#3520](http://projects.theforeman.org/issues/3520))
9
+ * Properly detect booleans ([#17021](http://projects.theforeman.org/issues/17021))
10
+ * Support for additional text in help ([PR #222](https://github.com/theforeman/hammer-cli/pull/222)) ([#16408](http://projects.theforeman.org/issues/16408))
11
+ * Permit clamp 1.1 and higher, compatibility restored ([PR #224](https://github.com/theforeman/hammer-cli/pull/224)) ([#16973](http://projects.theforeman.org/issues/16973))
12
+ * Pin clamp to 1.0.x ([PR #223](https://github.com/theforeman/hammer-cli/pull/223)) ([#16973](http://projects.theforeman.org/issues/16973))
13
+ * Allow multiple opt validation blocks ([#16811](http://projects.theforeman.org/issues/16811))
14
+ * Check for nil default values ([PR #221](https://github.com/theforeman/hammer-cli/pull/221)) ([#16822](http://projects.theforeman.org/issues/16822))
15
+ * Use defaults in validators ([#16631](http://projects.theforeman.org/issues/16631))
16
+ * Boolean formatter prints "no" for 0 ([PR #219](https://github.com/theforeman/hammer-cli/pull/219)) ([#16406](http://projects.theforeman.org/issues/16406))
17
+ * Fix mark_translated in cli_config ([PR #216](https://github.com/theforeman/hammer-cli/pull/216)) ([#16470](http://projects.theforeman.org/issues/16470))
18
+
4
19
  ### 0.8.0 (2016-09-01)
5
20
  * Fix tests with rest-client >= 2.0.0 ([#16404](http://projects.theforeman.org/issues/16404))
6
21
  * Add missing apostrophe in error message ([#16316](http://projects.theforeman.org/issues/16316))
@@ -4,6 +4,8 @@ require 'hammer_cli/options/option_definition'
4
4
  require 'hammer_cli/clamp'
5
5
  require 'hammer_cli/subcommand'
6
6
  require 'hammer_cli/options/matcher'
7
+ require 'hammer_cli/help/builder'
8
+ require 'hammer_cli/help/text_builder'
7
9
  require 'logging'
8
10
  module HammerCLI
9
11
 
@@ -11,7 +13,7 @@ module HammerCLI
11
13
  include HammerCLI::Subcommand
12
14
 
13
15
  class << self
14
- attr_accessor :validation_block
16
+ attr_accessor :validation_blocks
15
17
  end
16
18
 
17
19
  def adapter
@@ -39,11 +41,14 @@ module HammerCLI
39
41
  end
40
42
 
41
43
  def self.validate_options(&block)
42
- self.validation_block = block
44
+ self.validation_blocks ||= []
45
+ self.validation_blocks << block
43
46
  end
44
47
 
45
48
  def validate_options
46
- validator.run &self.class.validation_block if self.class.validation_block
49
+ if self.class.validation_blocks && self.class.validation_blocks.any?
50
+ self.class.validation_blocks.each { |validation_block| validator.run(&validation_block) }
51
+ end
47
52
  end
48
53
 
49
54
  def exception_handler
@@ -60,38 +65,24 @@ module HammerCLI
60
65
  context[:path][-2]
61
66
  end
62
67
 
63
- class SortedBuilder < Clamp::Help::Builder
64
-
65
- def default_label_indent
66
- 29
67
- end
68
-
69
- def add_list(heading, items)
70
- items.sort! do |a, b|
71
- a.help[0] <=> b.help[0]
72
- end
73
- items.reject! {|item| item.respond_to?(:hidden?) && item.hidden?}
74
-
75
- puts "\n#{heading}:"
68
+ def help
69
+ self.class.help(invocation_path, HammerCLI::Help::Builder.new(context[:is_tty?]))
70
+ end
76
71
 
77
- label_width = default_label_indent
78
- items.each do |item|
79
- label, description = item.help
80
- label_width = label.size if label.size > label_width
81
- end
72
+ def self.help(invocation_path, builder = HammerCLI::Help::Builder.new)
73
+ super(invocation_path, builder)
82
74
 
83
- items.each do |item|
84
- label, description = item.help
85
- description.each_line do |line|
86
- puts " %-#{label_width}s %s" % [label, line]
87
- label = ''
88
- end
89
- end
75
+ if @help_extension_block
76
+ help_extension = HammerCLI::Help::TextBuilder.new(builder.richtext)
77
+ @help_extension_block.call(help_extension)
78
+ builder.add_text(help_extension.string)
90
79
  end
80
+ builder.string
91
81
  end
92
82
 
93
- def help
94
- self.class.help(invocation_path, SortedBuilder.new)
83
+ def self.extend_help(&block)
84
+ # We save the block for execution on object level, where we can access command's context and check :is_tty? flag
85
+ @help_extension_block = block
95
86
  end
96
87
 
97
88
  def self.output(definition=nil, &block)
@@ -254,7 +245,7 @@ module HammerCLI
254
245
  value
255
246
  end
256
247
  end
257
-
248
+
258
249
  def self.inherited_output_definition
259
250
  od = nil
260
251
  if superclass.respond_to? :output_definition
@@ -1,2 +1,3 @@
1
1
  require File.join(File.dirname(__FILE__), './apipie/option_builder')
2
+ require File.join(File.dirname(__FILE__), './apipie/api_connection')
2
3
  require File.join(File.dirname(__FILE__), './apipie/command')
@@ -0,0 +1,27 @@
1
+ require 'apipie_bindings'
2
+ module HammerCLI::Apipie
3
+ class ApiConnection < HammerCLI::AbstractConnector
4
+ attr_reader :api
5
+
6
+ def initialize(params, options = {})
7
+ @logger = options[:logger]
8
+ @api = ApipieBindings::API.new(params)
9
+ if options[:reload_cache]
10
+ @api.clean_cache
11
+ @logger.debug 'Apipie cache was cleared' unless @logger.nil?
12
+ end
13
+ end
14
+
15
+ def resources
16
+ @api.resources
17
+ end
18
+
19
+ def resource(resource_name)
20
+ @api.resource(resource_name)
21
+ end
22
+
23
+ def has_resource?(resource_name)
24
+ @api.has_resource?(resource_name)
25
+ end
26
+ end
27
+ end
@@ -64,14 +64,14 @@ module HammerCLI::Apipie
64
64
  def option_opts(param)
65
65
  opts = {}
66
66
  opts[:required] = true if (param.required? and require_options?)
67
- if param.expected_type == :array || param.validator =~ /Array/i
67
+ if param.expected_type.to_s == 'array' || param.validator =~ /Array/i
68
68
  opts[:format] = HammerCLI::Options::Normalizers::List.new
69
- elsif param.expected_type == 'boolean' || param.validator =~ /Boolean/i
69
+ elsif param.expected_type.to_s == 'boolean' || param.validator =~ /Boolean/i
70
70
  opts[:format] = HammerCLI::Options::Normalizers::Bool.new
71
71
  elsif param.validator =~ /Must be one of: (.*)\./
72
72
  allowed = $1.split(/,\ ?/).map { |val| val.gsub(/<[^>]*>/i,'') }
73
73
  opts[:format] = HammerCLI::Options::Normalizers::Enum.new(allowed)
74
- elsif param.expected_type == 'number' || param.validator =~ /Number/i
74
+ elsif param.expected_type.to_s == 'number' || param.validator =~ /Number/i
75
75
  opts[:format] = HammerCLI::Options::Normalizers::Number.new
76
76
  end
77
77
  opts[:attribute_name] = HammerCLI.option_accessor_name(param.name)
@@ -1,21 +1,5 @@
1
1
  require 'apipie_bindings'
2
2
  module HammerCLI::Apipie
3
-
4
-
5
- class ApipieConnector < HammerCLI::AbstractConnector
6
-
7
- attr_reader :api
8
-
9
- def initialize(params)
10
- @api = ApipieBindings::API.new(params)
11
- if HammerCLI::Settings.get(:_params, :reload_cache) || HammerCLI::Settings.get(:reload_cache)
12
- @api.clean_cache
13
- Logging.logger['Init'].debug 'Apipie cache was cleared'
14
- end
15
- end
16
- end
17
-
18
-
19
3
  module Resource
20
4
 
21
5
  def self.included(base)
@@ -44,12 +28,6 @@ module HammerCLI::Apipie
44
28
  {}
45
29
  end
46
30
 
47
- def connection_options
48
- {
49
- :connector => HammerCLI::Apipie::ApipieConnector
50
- }
51
- end
52
-
53
31
  def connection_name(resource_class)
54
32
  :apipie
55
33
  end
@@ -70,10 +48,7 @@ module HammerCLI::Apipie
70
48
 
71
49
  def resource(resource=nil, action=nil)
72
50
  unless resource.nil?
73
- api = HammerCLI::Connection.create(
74
- connection_name(resource),
75
- resource_config,
76
- connection_options).api
51
+ api = HammerCLI.context[:api_connection].get(connection_name(resource))
77
52
  if api.has_resource?(resource)
78
53
  @api_resource = api.resource(resource)
79
54
  else
@@ -6,39 +6,40 @@ module HammerCLI
6
6
  end
7
7
 
8
8
  class Connection
9
+ def initialize(logger = nil)
10
+ @logger = logger
11
+ end
9
12
 
10
- def self.drop(name)
13
+ def drop(name)
11
14
  connections.delete(name)
12
15
  end
13
16
 
14
- def self.drop_all()
17
+ def drop_all()
15
18
  connections.keys.each { |c| drop(c) }
16
19
  end
17
20
 
18
- def self.create(name, conector_params={}, options={})
21
+ def create(name, &create_connector_block)
19
22
  unless connections[name]
20
- Logging.logger['Connection'].debug "Registered: #{name}"
21
- connector = options[:connector] || AbstractConnector
22
-
23
- connections[name] = connector.new(conector_params)
23
+ connector = yield
24
+ @logger.debug("Registered: #{name}") if @logger
25
+ connections[name] = connector
24
26
  end
25
27
  connections[name]
26
28
  end
27
29
 
28
- def self.exist?(name)
30
+ def exist?(name)
29
31
  !get(name).nil?
30
32
  end
31
33
 
32
- def self.get(name)
34
+ def get(name)
33
35
  connections[name]
34
36
  end
35
37
 
36
38
  private
37
39
 
38
- def self.connections
40
+ def connections
39
41
  @connections_hash ||= {}
40
42
  @connections_hash
41
43
  end
42
-
43
44
  end
44
45
  end
@@ -3,8 +3,10 @@ require 'hammer_cli/defaults'
3
3
  module HammerCLI
4
4
 
5
5
  def self.context
6
- {
7
- :defaults => HammerCLI.defaults
6
+ @context ||= {
7
+ :defaults => HammerCLI.defaults,
8
+ :is_tty? => HammerCLI.tty?,
9
+ :api_connection => HammerCLI::Connection.new(Logging.logger['Connection'])
8
10
  }
9
11
  end
10
12
 
@@ -83,7 +83,7 @@ module HammerCLI
83
83
  end
84
84
 
85
85
  def handle_unauthorized(e)
86
- print_error _("Invalid username or password")
86
+ print_error e.message
87
87
  log_full_error e
88
88
  HammerCLI::EX_UNAUTHORIZED
89
89
  end
@@ -0,0 +1,58 @@
1
+ module HammerCLI
2
+ module Help
3
+ class Builder < Clamp::Help::Builder
4
+ DEFAULT_LABEL_INDENT = 29
5
+
6
+ attr_reader :richtext
7
+
8
+ def initialize(richtext = false)
9
+ super()
10
+ @richtext = richtext
11
+ end
12
+
13
+ def add_usage(invocation_path, usage_descriptions)
14
+ heading(Clamp.message(:usage_heading))
15
+ usage_descriptions.each do |usage|
16
+ puts " #{invocation_path} #{usage}".rstrip
17
+ end
18
+ end
19
+
20
+ def add_list(heading, items)
21
+ items.sort! do |a, b|
22
+ a.help[0] <=> b.help[0]
23
+ end
24
+ items.reject! {|item| item.respond_to?(:hidden?) && item.hidden?}
25
+
26
+ puts
27
+ heading(heading)
28
+
29
+ label_width = DEFAULT_LABEL_INDENT
30
+ items.each do |item|
31
+ label, description = item.help
32
+ label_width = label.size if label.size > label_width
33
+ end
34
+
35
+ items.each do |item|
36
+ label, description = item.help
37
+ description.each_line do |line|
38
+ puts " %-#{label_width}s %s" % [label, line]
39
+ label = ''
40
+ end
41
+ end
42
+ end
43
+
44
+ def add_text(content)
45
+ puts
46
+ puts content
47
+ end
48
+
49
+ protected
50
+
51
+ def heading(label)
52
+ label = "#{label}:"
53
+ label = HighLine.color(label, :bold) if @richtext
54
+ puts label
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,79 @@
1
+ module HammerCLI
2
+ module Help
3
+ class TextBuilder
4
+ INDENT_STEP = 2
5
+ LIST_INDENT = 20
6
+
7
+ def initialize(richtext = false)
8
+ @out = StringIO.new
9
+ @richtext = richtext
10
+ end
11
+
12
+ def string
13
+ @out.string
14
+ end
15
+
16
+ def text(content)
17
+ puts unless first_print?
18
+ puts content
19
+ end
20
+
21
+ def list(items)
22
+ return if items.empty?
23
+
24
+ items = normalize_list(items)
25
+ max_len = items.map { |i| i[0].to_s.length }.max
26
+ indent_size = (max_len + INDENT_STEP > LIST_INDENT) ? (max_len + INDENT_STEP) : LIST_INDENT
27
+
28
+ puts unless first_print?
29
+ items.each do |col1, col2|
30
+ # handle multiple lines in the second column
31
+ col2 = indent(col2.to_s, ' ' * indent_size).lstrip
32
+
33
+ line = "%-#{indent_size}s%s" % [col1, col2]
34
+ line.strip!
35
+ puts line
36
+ end
37
+ end
38
+
39
+ def section(label, &block)
40
+ puts unless first_print?
41
+ heading(label)
42
+
43
+ sub_builder = TextBuilder.new(@richtext)
44
+ yield(sub_builder) if block_given?
45
+ puts indent(sub_builder.string)
46
+ end
47
+
48
+ def indent(content, indentation = nil)
49
+ indentation ||= " " * INDENT_STEP
50
+ content = content.split("\n") unless content.is_a? Array
51
+ content.map do |line|
52
+ (indentation + line).rstrip
53
+ end.join("\n")
54
+ end
55
+
56
+ protected
57
+
58
+ def heading(label)
59
+ label = "#{label}:"
60
+ label = HighLine.color(label, :bold) if @richtext
61
+ puts label
62
+ end
63
+
64
+ def puts(*args)
65
+ @out.puts(*args)
66
+ end
67
+
68
+ def first_print?
69
+ @out.size == 0
70
+ end
71
+
72
+ def normalize_list(items)
73
+ items.map do |i|
74
+ i.is_a?(Array) ? i : [i]
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end