rubygems-update 3.4.21 → 3.4.22

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 (113) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -0
  3. data/Manifest.txt +5 -0
  4. data/bundler/CHANGELOG.md +21 -0
  5. data/bundler/README.md +1 -2
  6. data/bundler/lib/bundler/build_metadata.rb +2 -2
  7. data/bundler/lib/bundler/cli/gem.rb +3 -0
  8. data/bundler/lib/bundler/definition.rb +1 -1
  9. data/bundler/lib/bundler/endpoint_specification.rb +1 -1
  10. data/bundler/lib/bundler/errors.rb +15 -0
  11. data/bundler/lib/bundler/gem_helpers.rb +7 -0
  12. data/bundler/lib/bundler/installer/gem_installer.rb +5 -5
  13. data/bundler/lib/bundler/lazy_specification.rb +4 -0
  14. data/bundler/lib/bundler/plugin/index.rb +8 -0
  15. data/bundler/lib/bundler/plugin.rb +9 -2
  16. data/bundler/lib/bundler/rubygems_ext.rb +3 -4
  17. data/bundler/lib/bundler/rubygems_gem_installer.rb +23 -8
  18. data/bundler/lib/bundler/source/git/git_proxy.rb +9 -1
  19. data/bundler/lib/bundler/source/metadata.rb +1 -1
  20. data/bundler/lib/bundler/spec_set.rb +5 -2
  21. data/bundler/lib/bundler/templates/newgem/newgem.gemspec.tt +1 -1
  22. data/bundler/lib/bundler/ui/shell.rb +1 -1
  23. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/connection.rb +1 -0
  24. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent/pool.rb +21 -9
  25. data/bundler/lib/bundler/vendor/net-http-persistent/lib/net/http/persistent.rb +1 -1
  26. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/create_file.rb +3 -2
  27. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/directory.rb +1 -1
  28. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/empty_directory.rb +1 -1
  29. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +8 -10
  30. data/bundler/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb +15 -4
  31. data/bundler/lib/bundler/vendor/thor/lib/thor/actions.rb +15 -15
  32. data/bundler/lib/bundler/vendor/thor/lib/thor/base.rb +140 -14
  33. data/bundler/lib/bundler/vendor/thor/lib/thor/command.rb +13 -4
  34. data/bundler/lib/bundler/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +4 -0
  35. data/bundler/lib/bundler/vendor/thor/lib/thor/error.rb +16 -25
  36. data/bundler/lib/bundler/vendor/thor/lib/thor/group.rb +1 -1
  37. data/bundler/lib/bundler/vendor/thor/lib/thor/invocation.rb +1 -1
  38. data/bundler/lib/bundler/vendor/thor/lib/thor/nested_context.rb +2 -2
  39. data/bundler/lib/bundler/vendor/thor/lib/thor/parser/argument.rb +20 -1
  40. data/bundler/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +33 -17
  41. data/bundler/lib/bundler/vendor/thor/lib/thor/parser/option.rb +27 -8
  42. data/bundler/lib/bundler/vendor/thor/lib/thor/parser/options.rb +44 -6
  43. data/bundler/lib/bundler/vendor/thor/lib/thor/rake_compat.rb +2 -2
  44. data/bundler/lib/bundler/vendor/thor/lib/thor/runner.rb +40 -30
  45. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +26 -150
  46. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/color.rb +4 -46
  47. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/column_printer.rb +29 -0
  48. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/html.rb +3 -45
  49. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/lcs_diff.rb +49 -0
  50. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/table_printer.rb +134 -0
  51. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/terminal.rb +42 -0
  52. data/bundler/lib/bundler/vendor/thor/lib/thor/shell/wrapped_printer.rb +38 -0
  53. data/bundler/lib/bundler/vendor/thor/lib/thor/shell.rb +1 -1
  54. data/bundler/lib/bundler/vendor/thor/lib/thor/util.rb +8 -7
  55. data/bundler/lib/bundler/vendor/thor/lib/thor/version.rb +1 -1
  56. data/bundler/lib/bundler/vendor/thor/lib/thor.rb +155 -8
  57. data/bundler/lib/bundler/version.rb +1 -1
  58. data/bundler/lib/bundler/yaml_serializer.rb +6 -1
  59. data/bundler/lib/bundler.rb +0 -8
  60. data/lib/rubygems/command.rb +3 -3
  61. data/lib/rubygems/commands/cert_command.rb +1 -1
  62. data/lib/rubygems/commands/contents_command.rb +1 -1
  63. data/lib/rubygems/commands/environment_command.rb +2 -2
  64. data/lib/rubygems/commands/help_command.rb +1 -1
  65. data/lib/rubygems/commands/setup_command.rb +2 -2
  66. data/lib/rubygems/commands/uninstall_command.rb +4 -4
  67. data/lib/rubygems/commands/unpack_command.rb +3 -3
  68. data/lib/rubygems/commands/update_command.rb +1 -1
  69. data/lib/rubygems/config_file.rb +3 -3
  70. data/lib/rubygems/core_ext/kernel_require.rb +1 -1
  71. data/lib/rubygems/dependency_installer.rb +4 -4
  72. data/lib/rubygems/doctor.rb +1 -1
  73. data/lib/rubygems/ext/ext_conf_builder.rb +1 -1
  74. data/lib/rubygems/ext/rake_builder.rb +1 -1
  75. data/lib/rubygems/installer.rb +7 -12
  76. data/lib/rubygems/local_remote_options.rb +1 -1
  77. data/lib/rubygems/package/digest_io.rb +1 -1
  78. data/lib/rubygems/package/tar_header.rb +2 -2
  79. data/lib/rubygems/package/tar_reader.rb +9 -2
  80. data/lib/rubygems/package/tar_writer.rb +1 -1
  81. data/lib/rubygems/package.rb +1 -1
  82. data/lib/rubygems/path_support.rb +1 -1
  83. data/lib/rubygems/platform.rb +6 -4
  84. data/lib/rubygems/remote_fetcher.rb +2 -2
  85. data/lib/rubygems/request.rb +1 -1
  86. data/lib/rubygems/request_set/gem_dependency_api.rb +1 -1
  87. data/lib/rubygems/resolver.rb +3 -3
  88. data/lib/rubygems/security/trust_dir.rb +1 -1
  89. data/lib/rubygems/source/local.rb +2 -1
  90. data/lib/rubygems/source_list.rb +1 -1
  91. data/lib/rubygems/spec_fetcher.rb +2 -2
  92. data/lib/rubygems/specification.rb +21 -13
  93. data/lib/rubygems/specification_policy.rb +6 -6
  94. data/lib/rubygems/uninstaller.rb +2 -2
  95. data/lib/rubygems/user_interaction.rb +2 -2
  96. data/lib/rubygems/util/licenses.rb +48 -0
  97. data/lib/rubygems/validator.rb +1 -1
  98. data/lib/rubygems/version.rb +3 -3
  99. data/lib/rubygems/yaml_serializer.rb +6 -1
  100. data/lib/rubygems.rb +6 -6
  101. data/rubygems-update.gemspec +1 -1
  102. data/test/rubygems/helper.rb +6 -6
  103. data/test/rubygems/test_gem_command_manager.rb +6 -6
  104. data/test/rubygems/test_gem_commands_cert_command.rb +1 -1
  105. data/test/rubygems/test_gem_commands_install_command.rb +2 -2
  106. data/test/rubygems/test_gem_commands_uninstall_command.rb +20 -0
  107. data/test/rubygems/test_gem_ext_builder.rb +1 -1
  108. data/test/rubygems/test_gem_installer.rb +1 -1
  109. data/test/rubygems/test_gem_package_tar_reader.rb +15 -0
  110. data/test/rubygems/test_gem_security_policy.rb +2 -2
  111. data/test/rubygems/test_gem_stream_ui.rb +1 -1
  112. data/test/rubygems/utilities.rb +2 -2
  113. metadata +8 -3
@@ -0,0 +1,49 @@
1
+ module LCSDiff
2
+ protected
3
+
4
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
5
+ # available.
6
+ def show_diff(destination, content) #:nodoc:
7
+ if diff_lcs_loaded? && ENV["THOR_DIFF"].nil? && ENV["RAILS_DIFF"].nil?
8
+ actual = File.binread(destination).to_s.split("\n")
9
+ content = content.to_s.split("\n")
10
+
11
+ Diff::LCS.sdiff(actual, content).each do |diff|
12
+ output_diff_line(diff)
13
+ end
14
+ else
15
+ super
16
+ end
17
+ end
18
+
19
+ private
20
+
21
+ def output_diff_line(diff) #:nodoc:
22
+ case diff.action
23
+ when "-"
24
+ say "- #{diff.old_element.chomp}", :red, true
25
+ when "+"
26
+ say "+ #{diff.new_element.chomp}", :green, true
27
+ when "!"
28
+ say "- #{diff.old_element.chomp}", :red, true
29
+ say "+ #{diff.new_element.chomp}", :green, true
30
+ else
31
+ say " #{diff.old_element.chomp}", nil, true
32
+ end
33
+ end
34
+
35
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
36
+ # for diff.
37
+ def diff_lcs_loaded? #:nodoc:
38
+ return true if defined?(Diff::LCS)
39
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
40
+
41
+ @diff_lcs_loaded = begin
42
+ require "diff/lcs"
43
+ true
44
+ rescue LoadError
45
+ false
46
+ end
47
+ end
48
+
49
+ end
@@ -0,0 +1,134 @@
1
+ require_relative "column_printer"
2
+ require_relative "terminal"
3
+
4
+ class Bundler::Thor
5
+ module Shell
6
+ class TablePrinter < ColumnPrinter
7
+ BORDER_SEPARATOR = :separator
8
+
9
+ def initialize(stdout, options = {})
10
+ super
11
+ @formats = []
12
+ @maximas = []
13
+ @colwidth = options[:colwidth]
14
+ @truncate = options[:truncate] == true ? Terminal.terminal_width : options[:truncate]
15
+ @padding = 1
16
+ end
17
+
18
+ def print(array)
19
+ return if array.empty?
20
+
21
+ prepare(array)
22
+
23
+ print_border_separator if options[:borders]
24
+
25
+ array.each do |row|
26
+ if options[:borders] && row == BORDER_SEPARATOR
27
+ print_border_separator
28
+ next
29
+ end
30
+
31
+ sentence = "".dup
32
+
33
+ row.each_with_index do |column, index|
34
+ sentence << format_cell(column, row.size, index)
35
+ end
36
+
37
+ sentence = truncate(sentence)
38
+ sentence << "|" if options[:borders]
39
+ stdout.puts indentation + sentence
40
+
41
+ end
42
+ print_border_separator if options[:borders]
43
+ end
44
+
45
+ private
46
+
47
+ def prepare(array)
48
+ array = array.reject{|row| row == BORDER_SEPARATOR }
49
+
50
+ @formats << "%-#{@colwidth + 2}s".dup if @colwidth
51
+ start = @colwidth ? 1 : 0
52
+
53
+ colcount = array.max { |a, b| a.size <=> b.size }.size
54
+
55
+ start.upto(colcount - 1) do |index|
56
+ maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
57
+
58
+ @maximas << maxima
59
+ @formats << if options[:borders]
60
+ "%-#{maxima}s".dup
61
+ elsif index == colcount - 1
62
+ # Don't output 2 trailing spaces when printing the last column
63
+ "%-s".dup
64
+ else
65
+ "%-#{maxima + 2}s".dup
66
+ end
67
+ end
68
+
69
+ @formats << "%s"
70
+ end
71
+
72
+ def format_cell(column, row_size, index)
73
+ maxima = @maximas[index]
74
+
75
+ f = if column.is_a?(Numeric)
76
+ if options[:borders]
77
+ # With borders we handle padding separately
78
+ "%#{maxima}s"
79
+ elsif index == row_size - 1
80
+ # Don't output 2 trailing spaces when printing the last column
81
+ "%#{maxima}s"
82
+ else
83
+ "%#{maxima}s "
84
+ end
85
+ else
86
+ @formats[index]
87
+ end
88
+
89
+ cell = "".dup
90
+ cell << "|" + " " * @padding if options[:borders]
91
+ cell << f % column.to_s
92
+ cell << " " * @padding if options[:borders]
93
+ cell
94
+ end
95
+
96
+ def print_border_separator
97
+ separator = @maximas.map do |maxima|
98
+ "+" + "-" * (maxima + 2 * @padding)
99
+ end
100
+ stdout.puts indentation + separator.join + "+"
101
+ end
102
+
103
+ def truncate(string)
104
+ return string unless @truncate
105
+ as_unicode do
106
+ chars = string.chars.to_a
107
+ if chars.length <= @truncate
108
+ chars.join
109
+ else
110
+ chars[0, @truncate - 3 - @indent].join + "..."
111
+ end
112
+ end
113
+ end
114
+
115
+ def indentation
116
+ " " * @indent
117
+ end
118
+
119
+ if "".respond_to?(:encode)
120
+ def as_unicode
121
+ yield
122
+ end
123
+ else
124
+ def as_unicode
125
+ old = $KCODE # rubocop:disable Style/GlobalVars
126
+ $KCODE = "U" # rubocop:disable Style/GlobalVars
127
+ yield
128
+ ensure
129
+ $KCODE = old # rubocop:disable Style/GlobalVars
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,42 @@
1
+ class Bundler::Thor
2
+ module Shell
3
+ module Terminal
4
+ DEFAULT_TERMINAL_WIDTH = 80
5
+
6
+ class << self
7
+ # This code was copied from Rake, available under MIT-LICENSE
8
+ # Copyright (c) 2003, 2004 Jim Weirich
9
+ def terminal_width
10
+ result = if ENV["THOR_COLUMNS"]
11
+ ENV["THOR_COLUMNS"].to_i
12
+ else
13
+ unix? ? dynamic_width : DEFAULT_TERMINAL_WIDTH
14
+ end
15
+ result < 10 ? DEFAULT_TERMINAL_WIDTH : result
16
+ rescue
17
+ DEFAULT_TERMINAL_WIDTH
18
+ end
19
+
20
+ def unix?
21
+ RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris)/i
22
+ end
23
+
24
+ private
25
+
26
+ # Calculate the dynamic width of the terminal
27
+ def dynamic_width
28
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
29
+ end
30
+
31
+ def dynamic_width_stty
32
+ `stty size 2>/dev/null`.split[1].to_i
33
+ end
34
+
35
+ def dynamic_width_tput
36
+ `tput cols 2>/dev/null`.to_i
37
+ end
38
+
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,38 @@
1
+ require_relative "column_printer"
2
+ require_relative "terminal"
3
+
4
+ class Bundler::Thor
5
+ module Shell
6
+ class WrappedPrinter < ColumnPrinter
7
+ def print(message)
8
+ width = Terminal.terminal_width - @indent
9
+ paras = message.split("\n\n")
10
+
11
+ paras.map! do |unwrapped|
12
+ words = unwrapped.split(" ")
13
+ counter = words.first.length
14
+ words.inject do |memo, word|
15
+ word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
16
+ counter = 0 if word.include? "\n"
17
+ if (counter + word.length + 1) < width
18
+ memo = "#{memo} #{word}"
19
+ counter += (word.length + 1)
20
+ else
21
+ memo = "#{memo}\n#{word}"
22
+ counter = word.length
23
+ end
24
+ memo
25
+ end
26
+ end.compact!
27
+
28
+ paras.each do |para|
29
+ para.split("\n").each do |line|
30
+ stdout.puts line.insert(0, " " * @indent)
31
+ end
32
+ stdout.puts unless para == paras.last
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+
@@ -75,7 +75,7 @@ class Bundler::Thor
75
75
  # Allow shell to be shared between invocations.
76
76
  #
77
77
  def _shared_configuration #:nodoc:
78
- super.merge!(:shell => shell)
78
+ super.merge!(shell: shell)
79
79
  end
80
80
  end
81
81
  end
@@ -90,7 +90,7 @@ class Bundler::Thor
90
90
  def snake_case(str)
91
91
  return str.downcase if str =~ /^[A-Z_]+$/
92
92
  str.gsub(/\B[A-Z]/, '_\&').squeeze("_") =~ /_*(.*)/
93
- $+.downcase
93
+ Regexp.last_match(-1).downcase
94
94
  end
95
95
 
96
96
  # Receives a string and convert it to camel case. camel_case returns CamelCase.
@@ -130,9 +130,10 @@ class Bundler::Thor
130
130
  #
131
131
  def find_class_and_command_by_namespace(namespace, fallback = true)
132
132
  if namespace.include?(":") # look for a namespaced command
133
- pieces = namespace.split(":")
134
- command = pieces.pop
135
- klass = Bundler::Thor::Util.find_by_namespace(pieces.join(":"))
133
+ *pieces, command = namespace.split(":")
134
+ namespace = pieces.join(":")
135
+ namespace = "default" if namespace.empty?
136
+ klass = Bundler::Thor::Base.subclasses.detect { |thor| thor.namespace == namespace && thor.commands.keys.include?(command) }
136
137
  end
137
138
  unless klass # look for a Bundler::Thor::Group with the right name
138
139
  klass = Bundler::Thor::Util.find_by_namespace(namespace)
@@ -150,7 +151,7 @@ class Bundler::Thor
150
151
  # inside the sandbox to avoid namespacing conflicts.
151
152
  #
152
153
  def load_thorfile(path, content = nil, debug = false)
153
- content ||= File.binread(path)
154
+ content ||= File.read(path)
154
155
 
155
156
  begin
156
157
  Bundler::Thor::Sandbox.class_eval(content, path)
@@ -189,7 +190,7 @@ class Bundler::Thor
189
190
  # Returns the root where thor files are located, depending on the OS.
190
191
  #
191
192
  def thor_root
192
- File.join(user_home, ".thor").tr('\\', "/")
193
+ File.join(user_home, ".thor").tr("\\", "/")
193
194
  end
194
195
 
195
196
  # Returns the files in the thor root. On Windows thor_root will be something
@@ -236,7 +237,7 @@ class Bundler::Thor
236
237
  # symlink points to 'ruby_install_name'
237
238
  ruby = alternate_ruby if linked_ruby == ruby_name || linked_ruby == ruby
238
239
  end
239
- rescue NotImplementedError # rubocop:disable HandleExceptions
240
+ rescue NotImplementedError # rubocop:disable Lint/HandleExceptions
240
241
  # just ignore on windows
241
242
  end
242
243
  end
@@ -1,3 +1,3 @@
1
1
  class Bundler::Thor
2
- VERSION = "1.2.1"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -65,8 +65,15 @@ class Bundler::Thor
65
65
 
66
66
  # Defines the long description of the next command.
67
67
  #
68
+ # Long description is by default indented, line-wrapped and repeated whitespace merged.
69
+ # In order to print long description verbatim, with indentation and spacing exactly
70
+ # as found in the code, use the +wrap+ option
71
+ #
72
+ # long_desc 'your very long description', wrap: false
73
+ #
68
74
  # ==== Parameters
69
75
  # long description<String>
76
+ # options<Hash>
70
77
  #
71
78
  def long_desc(long_description, options = {})
72
79
  if options[:for]
@@ -74,6 +81,7 @@ class Bundler::Thor
74
81
  command.long_description = long_description if long_description
75
82
  else
76
83
  @long_desc = long_description
84
+ @long_desc_wrap = options[:wrap] != false
77
85
  end
78
86
  end
79
87
 
@@ -133,7 +141,7 @@ class Bundler::Thor
133
141
  # # magic
134
142
  # end
135
143
  #
136
- # method_option :foo => :bar, :for => :previous_command
144
+ # method_option :foo, :for => :previous_command
137
145
  #
138
146
  # def next_command
139
147
  # # magic
@@ -153,6 +161,9 @@ class Bundler::Thor
153
161
  # :hide - If you want to hide this option from the help.
154
162
  #
155
163
  def method_option(name, options = {})
164
+ unless [ Symbol, String ].any? { |klass| name.is_a?(klass) }
165
+ raise ArgumentError, "Expected a Symbol or String, got #{name.inspect}"
166
+ end
156
167
  scope = if options[:for]
157
168
  find_and_refresh_command(options[:for]).options
158
169
  else
@@ -163,6 +174,81 @@ class Bundler::Thor
163
174
  end
164
175
  alias_method :option, :method_option
165
176
 
177
+ # Adds and declares option group for exclusive options in the
178
+ # block and arguments. You can declare options as the outside of the block.
179
+ #
180
+ # If :for is given as option, it allows you to change the options from
181
+ # a previous defined command.
182
+ #
183
+ # ==== Parameters
184
+ # Array[Bundler::Thor::Option.name]
185
+ # options<Hash>:: :for is applied for previous defined command.
186
+ #
187
+ # ==== Examples
188
+ #
189
+ # exclusive do
190
+ # option :one
191
+ # option :two
192
+ # end
193
+ #
194
+ # Or
195
+ #
196
+ # option :one
197
+ # option :two
198
+ # exclusive :one, :two
199
+ #
200
+ # If you give "--one" and "--two" at the same time ExclusiveArgumentsError
201
+ # will be raised.
202
+ #
203
+ def method_exclusive(*args, &block)
204
+ register_options_relation_for(:method_options,
205
+ :method_exclusive_option_names, *args, &block)
206
+ end
207
+ alias_method :exclusive, :method_exclusive
208
+
209
+ # Adds and declares option group for required at least one of options in the
210
+ # block of arguments. You can declare options as the outside of the block.
211
+ #
212
+ # If :for is given as option, it allows you to change the options from
213
+ # a previous defined command.
214
+ #
215
+ # ==== Parameters
216
+ # Array[Bundler::Thor::Option.name]
217
+ # options<Hash>:: :for is applied for previous defined command.
218
+ #
219
+ # ==== Examples
220
+ #
221
+ # at_least_one do
222
+ # option :one
223
+ # option :two
224
+ # end
225
+ #
226
+ # Or
227
+ #
228
+ # option :one
229
+ # option :two
230
+ # at_least_one :one, :two
231
+ #
232
+ # If you do not give "--one" and "--two" AtLeastOneRequiredArgumentError
233
+ # will be raised.
234
+ #
235
+ # You can use at_least_one and exclusive at the same time.
236
+ #
237
+ # exclusive do
238
+ # at_least_one do
239
+ # option :one
240
+ # option :two
241
+ # end
242
+ # end
243
+ #
244
+ # Then it is required either only one of "--one" or "--two".
245
+ #
246
+ def method_at_least_one(*args, &block)
247
+ register_options_relation_for(:method_options,
248
+ :method_at_least_one_option_names, *args, &block)
249
+ end
250
+ alias_method :at_least_one, :method_at_least_one
251
+
166
252
  # Prints help information for the given command.
167
253
  #
168
254
  # ==== Parameters
@@ -178,9 +264,16 @@ class Bundler::Thor
178
264
  shell.say " #{banner(command).split("\n").join("\n ")}"
179
265
  shell.say
180
266
  class_options_help(shell, nil => command.options.values)
267
+ print_exclusive_options(shell, command)
268
+ print_at_least_one_required_options(shell, command)
269
+
181
270
  if command.long_description
182
271
  shell.say "Description:"
183
- shell.print_wrapped(command.long_description, :indent => 2)
272
+ if command.wrap_long_description
273
+ shell.print_wrapped(command.long_description, indent: 2)
274
+ else
275
+ shell.say command.long_description
276
+ end
184
277
  else
185
278
  shell.say command.description
186
279
  end
@@ -197,7 +290,7 @@ class Bundler::Thor
197
290
  Bundler::Thor::Util.thor_classes_in(self).each do |klass|
198
291
  list += klass.printable_commands(false)
199
292
  end
200
- list.sort! { |a, b| a[0] <=> b[0] }
293
+ sort_commands!(list)
201
294
 
202
295
  if defined?(@package_name) && @package_name
203
296
  shell.say "#{@package_name} commands:"
@@ -205,9 +298,11 @@ class Bundler::Thor
205
298
  shell.say "Commands:"
206
299
  end
207
300
 
208
- shell.print_table(list, :indent => 2, :truncate => true)
301
+ shell.print_table(list, indent: 2, truncate: true)
209
302
  shell.say
210
303
  class_options_help(shell)
304
+ print_exclusive_options(shell)
305
+ print_at_least_one_required_options(shell)
211
306
  end
212
307
 
213
308
  # Returns commands ready to be printed.
@@ -238,7 +333,7 @@ class Bundler::Thor
238
333
 
239
334
  define_method(subcommand) do |*args|
240
335
  args, opts = Bundler::Thor::Arguments.split(args)
241
- invoke_args = [args, opts, {:invoked_via_subcommand => true, :class_options => options}]
336
+ invoke_args = [args, opts, {invoked_via_subcommand: true, class_options: options}]
242
337
  invoke_args.unshift "help" if opts.delete("--help") || opts.delete("-h")
243
338
  invoke subcommand_class, *invoke_args
244
339
  end
@@ -346,6 +441,24 @@ class Bundler::Thor
346
441
 
347
442
  protected
348
443
 
444
+ # Returns this class exclusive options array set.
445
+ #
446
+ # ==== Returns
447
+ # Array[Array[Bundler::Thor::Option.name]]
448
+ #
449
+ def method_exclusive_option_names #:nodoc:
450
+ @method_exclusive_option_names ||= []
451
+ end
452
+
453
+ # Returns this class at least one of required options array set.
454
+ #
455
+ # ==== Returns
456
+ # Array[Array[Bundler::Thor::Option.name]]
457
+ #
458
+ def method_at_least_one_option_names #:nodoc:
459
+ @method_at_least_one_option_names ||= []
460
+ end
461
+
349
462
  def stop_on_unknown_option #:nodoc:
350
463
  @stop_on_unknown_option ||= []
351
464
  end
@@ -355,8 +468,30 @@ class Bundler::Thor
355
468
  @disable_required_check ||= [:help]
356
469
  end
357
470
 
471
+ def print_exclusive_options(shell, command = nil) # :nodoc:
472
+ opts = []
473
+ opts = command.method_exclusive_option_names unless command.nil?
474
+ opts += class_exclusive_option_names
475
+ unless opts.empty?
476
+ shell.say "Exclusive Options:"
477
+ shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
478
+ shell.say
479
+ end
480
+ end
481
+
482
+ def print_at_least_one_required_options(shell, command = nil) # :nodoc:
483
+ opts = []
484
+ opts = command.method_at_least_one_option_names unless command.nil?
485
+ opts += class_at_least_one_option_names
486
+ unless opts.empty?
487
+ shell.say "Required At Least One:"
488
+ shell.print_table(opts.map{ |ex| ex.map{ |e| "--#{e}"}}, indent: 2 )
489
+ shell.say
490
+ end
491
+ end
492
+
358
493
  # The method responsible for dispatching given the args.
359
- def dispatch(meth, given_args, given_opts, config) #:nodoc: # rubocop:disable MethodLength
494
+ def dispatch(meth, given_args, given_opts, config) #:nodoc:
360
495
  meth ||= retrieve_command_name(given_args)
361
496
  command = all_commands[normalize_command_name(meth)]
362
497
 
@@ -415,12 +550,16 @@ class Bundler::Thor
415
550
  @usage ||= nil
416
551
  @desc ||= nil
417
552
  @long_desc ||= nil
553
+ @long_desc_wrap ||= nil
418
554
  @hide ||= nil
419
555
 
420
556
  if @usage && @desc
421
557
  base_class = @hide ? Bundler::Thor::HiddenCommand : Bundler::Thor::Command
422
- commands[meth] = base_class.new(meth, @desc, @long_desc, @usage, method_options)
423
- @usage, @desc, @long_desc, @method_options, @hide = nil
558
+ relations = {exclusive_option_names: method_exclusive_option_names,
559
+ at_least_one_option_names: method_at_least_one_option_names}
560
+ commands[meth] = base_class.new(meth, @desc, @long_desc, @long_desc_wrap, @usage, method_options, relations)
561
+ @usage, @desc, @long_desc, @long_desc_wrap, @method_options, @hide = nil
562
+ @method_exclusive_option_names, @method_at_least_one_option_names = nil
424
563
  true
425
564
  elsif all_commands[meth] || meth == "method_missing"
426
565
  true
@@ -495,6 +634,14 @@ class Bundler::Thor
495
634
  "
496
635
  end
497
636
  alias_method :subtask_help, :subcommand_help
637
+
638
+ # Sort the commands, lexicographically by default.
639
+ #
640
+ # Can be overridden in the subclass to change the display order of the
641
+ # commands.
642
+ def sort_commands!(list)
643
+ list.sort! { |a, b| a[0] <=> b[0] }
644
+ end
498
645
  end
499
646
 
500
647
  include Bundler::Thor::Base
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  module Bundler
4
- VERSION = "2.4.21".freeze
4
+ VERSION = "2.4.22".freeze
5
5
 
6
6
  def self.bundler_major_version
7
7
  @bundler_major_version ||= VERSION.split(".").first.to_i
@@ -17,7 +17,11 @@ module Bundler
17
17
  if v.is_a?(Hash)
18
18
  yaml << dump_hash(v).gsub(/^(?!$)/, " ") # indent all non-empty lines
19
19
  elsif v.is_a?(Array) # Expected to be array of strings
20
- yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
20
+ if v.empty?
21
+ yaml << " []\n"
22
+ else
23
+ yaml << "\n- " << v.map {|s| s.to_s.gsub(/\s+/, " ").inspect }.join("\n- ") << "\n"
24
+ end
21
25
  else
22
26
  yaml << " " << v.to_s.gsub(/\s+/, " ").inspect << "\n"
23
27
  end
@@ -63,6 +67,7 @@ module Bundler
63
67
  last_empty_key = key
64
68
  last_hash = stack[depth]
65
69
  else
70
+ val = [] if val == "[]" # empty array
66
71
  stack[depth][key] = val
67
72
  end
68
73
  elsif match = ARRAY_REGEX.match(line)
@@ -330,14 +330,6 @@ module Bundler
330
330
 
331
331
  def rm_rf(path)
332
332
  FileUtils.remove_entry_secure(path) if path && File.exist?(path)
333
- rescue ArgumentError
334
- message = <<EOF
335
- It is a security vulnerability to allow your home directory to be world-writable, and bundler cannot continue.
336
- You should probably consider fixing this issue by running `chmod o-w ~` on *nix.
337
- Please refer to https://ruby-doc.org/stdlib-3.1.2/libdoc/fileutils/rdoc/FileUtils.html#method-c-remove_entry_secure for details.
338
- EOF
339
- File.world_writable?(path) ? Bundler.ui.warn(message) : raise
340
- raise PathError, "Please fix the world-writable issue with your #{path} directory"
341
333
  end
342
334
 
343
335
  def settings
@@ -430,9 +430,9 @@ class Gem::Command
430
430
 
431
431
  def handles?(args)
432
432
  parser.parse!(args.dup)
433
- return true
433
+ true
434
434
  rescue StandardError
435
- return false
435
+ false
436
436
  end
437
437
 
438
438
  ##
@@ -459,7 +459,7 @@ class Gem::Command
459
459
  until extra.empty? do
460
460
  ex = []
461
461
  ex << extra.shift
462
- ex << extra.shift if extra.first.to_s =~ /^[^-]/ # rubocop:disable Performance/StartWith
462
+ ex << extra.shift if /^[^-]/.match?(extra.first.to_s) # rubocop:disable Performance/StartWith
463
463
  result << ex if handles?(ex)
464
464
  end
465
465
 
@@ -180,7 +180,7 @@ class Gem::Commands::CertCommand < Gem::Command
180
180
  key = Gem::Security.create_key(algorithm)
181
181
  key_path = Gem::Security.write key, "gem-private_key.pem", 0o600, passphrase
182
182
 
183
- return key, key_path
183
+ [key, key_path]
184
184
  end
185
185
 
186
186
  def certificates_matching(filter)
@@ -178,7 +178,7 @@ prefix or only the files that are requireable.
178
178
  @spec_dirs.sort.each {|dir| say dir }
179
179
  end
180
180
 
181
- return nil
181
+ nil
182
182
  end
183
183
 
184
184
  def specification_directories # :nodoc: