hammer_cli 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
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