bundler 1.5.1 → 1.5.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bundler might be problematic. Click here for more details.

Files changed (58) hide show
  1. data/CHANGELOG.md +26 -2
  2. data/bin/bundle +1 -3
  3. data/bundler.gemspec +1 -1
  4. data/lib/bundler/cli.rb +2 -4
  5. data/lib/bundler/fetcher.rb +13 -12
  6. data/lib/bundler/installer.rb +9 -36
  7. data/lib/bundler/parallel_workers/unix_worker.rb +12 -4
  8. data/lib/bundler/parallel_workers/worker.rb +1 -0
  9. data/lib/bundler/rubygems_ext.rb +1 -1
  10. data/lib/bundler/rubygems_integration.rb +15 -8
  11. data/lib/bundler/templates/newgem/newgem.gemspec.tt +1 -1
  12. data/lib/bundler/vendor/thor.rb +63 -56
  13. data/lib/bundler/vendor/thor/actions.rb +52 -51
  14. data/lib/bundler/vendor/thor/actions/create_file.rb +35 -37
  15. data/lib/bundler/vendor/thor/actions/create_link.rb +1 -2
  16. data/lib/bundler/vendor/thor/actions/directory.rb +36 -37
  17. data/lib/bundler/vendor/thor/actions/empty_directory.rb +67 -69
  18. data/lib/bundler/vendor/thor/actions/file_manipulation.rb +11 -12
  19. data/lib/bundler/vendor/thor/actions/inject_into_file.rb +41 -43
  20. data/lib/bundler/vendor/thor/base.rb +180 -178
  21. data/lib/bundler/vendor/thor/command.rb +22 -25
  22. data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +21 -24
  23. data/lib/bundler/vendor/thor/core_ext/io_binary_read.rb +1 -3
  24. data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +8 -10
  25. data/lib/bundler/vendor/thor/error.rb +2 -2
  26. data/lib/bundler/vendor/thor/group.rb +59 -60
  27. data/lib/bundler/vendor/thor/invocation.rb +39 -38
  28. data/lib/bundler/vendor/thor/line_editor.rb +17 -0
  29. data/lib/bundler/vendor/thor/line_editor/basic.rb +35 -0
  30. data/lib/bundler/vendor/thor/line_editor/readline.rb +88 -0
  31. data/lib/bundler/vendor/thor/parser/argument.rb +29 -30
  32. data/lib/bundler/vendor/thor/parser/arguments.rb +102 -98
  33. data/lib/bundler/vendor/thor/parser/option.rb +25 -25
  34. data/lib/bundler/vendor/thor/parser/options.rb +85 -85
  35. data/lib/bundler/vendor/thor/rake_compat.rb +6 -7
  36. data/lib/bundler/vendor/thor/runner.rb +154 -154
  37. data/lib/bundler/vendor/thor/shell.rb +23 -30
  38. data/lib/bundler/vendor/thor/shell/basic.rb +66 -57
  39. data/lib/bundler/vendor/thor/shell/color.rb +44 -43
  40. data/lib/bundler/vendor/thor/shell/html.rb +43 -44
  41. data/lib/bundler/vendor/thor/util.rb +37 -40
  42. data/lib/bundler/vendor/thor/version.rb +1 -1
  43. data/lib/bundler/version.rb +1 -1
  44. data/man/bundle-install.ronn +1 -1
  45. data/man/gemfile.5.ronn +1 -2
  46. data/spec/commands/binstubs_spec.rb +13 -0
  47. data/spec/install/gemfile/git_spec.rb +2 -2
  48. data/spec/install/gems/dependency_api_spec.rb +34 -0
  49. data/spec/install/gems/packed_spec.rb +2 -4
  50. data/spec/quality_spec.rb +2 -2
  51. data/spec/realworld/parallel_spec.rb +69 -0
  52. data/spec/runtime/setup_spec.rb +3 -2
  53. data/spec/spec_helper.rb +1 -0
  54. data/spec/support/artifice/endpoint_host_redirect.rb +15 -0
  55. data/spec/support/permissions.rb +11 -0
  56. metadata +11 -6
  57. data/spec/realworld/parallel_install_spec.rb +0 -23
  58. data/spec/realworld/parallel_update_spec.rb +0 -31
@@ -19,9 +19,9 @@ class Thor
19
19
  end
20
20
 
21
21
  # Make initializer aware of invocations and the initialization args.
22
- def initialize(args=[], options={}, config={}, &block) #:nodoc:
23
- @_invocations = config[:invocations] || Hash.new { |h,k| h[k] = [] }
24
- @_initializer = [ args, options, config ]
22
+ def initialize(args = [], options = {}, config = {}, &block) #:nodoc:
23
+ @_invocations = config[:invocations] || Hash.new { |h, k| h[k] = [] }
24
+ @_initializer = [args, options, config]
25
25
  super
26
26
  end
27
27
 
@@ -40,11 +40,11 @@ class Thor
40
40
  # class A < Thor
41
41
  # def foo
42
42
  # invoke :bar
43
- # invoke "b:hello", ["José"]
43
+ # invoke "b:hello", ["Erik"]
44
44
  # end
45
45
  #
46
46
  # def bar
47
- # invoke "b:hello", ["José"]
47
+ # invoke "b:hello", ["Erik"]
48
48
  # end
49
49
  # end
50
50
  #
@@ -93,17 +93,18 @@ class Thor
93
93
  #
94
94
  # invoke Rspec::RR, [], :style => :foo
95
95
  #
96
- def invoke(name=nil, *args)
96
+ def invoke(name = nil, *args)
97
97
  if name.nil?
98
98
  warn "[Thor] Calling invoke() without argument is deprecated. Please use invoke_all instead.\n#{caller.join("\n")}"
99
99
  return invoke_all
100
100
  end
101
101
 
102
- args.unshift(nil) if Array === args.first || NilClass === args.first
102
+ args.unshift(nil) if args.first.is_a?(Array) || args.first.nil?
103
103
  command, args, opts, config = args
104
104
 
105
105
  klass, command = _retrieve_class_and_command(name, command)
106
- raise "Expected Thor class, got #{klass}" unless klass <= Thor::Base
106
+ fail "Missing Thor class for invoke #{name}" unless klass
107
+ fail "Expected Thor class, got #{klass}" unless klass <= Thor::Base
107
108
 
108
109
  args, opts, config = _parse_initialization_options(args, opts, config)
109
110
  klass.send(:dispatch, command, args, opts, config) do |instance|
@@ -120,7 +121,7 @@ class Thor
120
121
  command.run(self, *args)
121
122
  end
122
123
  end
123
- alias invoke_task invoke_command
124
+ alias_method :invoke_task, :invoke_command
124
125
 
125
126
  # Invoke all commands for the current instance.
126
127
  def invoke_all #:nodoc:
@@ -132,41 +133,41 @@ class Thor
132
133
  with_padding { invoke(*args) }
133
134
  end
134
135
 
135
- protected
136
+ protected
136
137
 
137
- # Configuration values that are shared between invocations.
138
- def _shared_configuration #:nodoc:
139
- { :invocations => @_invocations }
140
- end
138
+ # Configuration values that are shared between invocations.
139
+ def _shared_configuration #:nodoc:
140
+ {:invocations => @_invocations}
141
+ end
141
142
 
142
- # This method simply retrieves the class and command to be invoked.
143
- # If the name is nil or the given name is a command in the current class,
144
- # use the given name and return self as class. Otherwise, call
145
- # prepare_for_invocation in the current class.
146
- def _retrieve_class_and_command(name, sent_command=nil) #:nodoc:
147
- case
148
- when name.nil?
149
- [self.class, nil]
150
- when self.class.all_commands[name.to_s]
151
- [self.class, name.to_s]
152
- else
153
- klass, command = self.class.prepare_for_invocation(nil, name)
154
- [klass, command || sent_command]
155
- end
143
+ # This method simply retrieves the class and command to be invoked.
144
+ # If the name is nil or the given name is a command in the current class,
145
+ # use the given name and return self as class. Otherwise, call
146
+ # prepare_for_invocation in the current class.
147
+ def _retrieve_class_and_command(name, sent_command = nil) #:nodoc:
148
+ case
149
+ when name.nil?
150
+ [self.class, nil]
151
+ when self.class.all_commands[name.to_s]
152
+ [self.class, name.to_s]
153
+ else
154
+ klass, command = self.class.prepare_for_invocation(nil, name)
155
+ [klass, command || sent_command]
156
156
  end
157
- alias _retrieve_class_and_task _retrieve_class_and_command
157
+ end
158
+ alias_method :_retrieve_class_and_task, :_retrieve_class_and_command
158
159
 
159
- # Initialize klass using values stored in the @_initializer.
160
- def _parse_initialization_options(args, opts, config) #:nodoc:
161
- stored_args, stored_opts, stored_config = @_initializer
160
+ # Initialize klass using values stored in the @_initializer.
161
+ def _parse_initialization_options(args, opts, config) #:nodoc:
162
+ stored_args, stored_opts, stored_config = @_initializer
162
163
 
163
- args ||= stored_args.dup
164
- opts ||= stored_opts.dup
164
+ args ||= stored_args.dup
165
+ opts ||= stored_opts.dup
165
166
 
166
- config ||= {}
167
- config = stored_config.merge(_shared_configuration).merge!(config)
167
+ config ||= {}
168
+ config = stored_config.merge(_shared_configuration).merge!(config)
168
169
 
169
- [ args, opts, config ]
170
- end
170
+ [args, opts, config]
171
+ end
171
172
  end
172
173
  end
@@ -0,0 +1,17 @@
1
+ require 'thor/line_editor/basic'
2
+ require 'thor/line_editor/readline'
3
+
4
+ class Thor
5
+ module LineEditor
6
+ def self.readline(prompt, options={})
7
+ best_available.new(prompt, options).readline
8
+ end
9
+
10
+ def self.best_available
11
+ [
12
+ Thor::LineEditor::Readline,
13
+ Thor::LineEditor::Basic
14
+ ].detect(&:available?)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,35 @@
1
+ class Thor
2
+ module LineEditor
3
+ class Basic
4
+ attr_reader :prompt, :options
5
+
6
+ def self.available?
7
+ true
8
+ end
9
+
10
+ def initialize(prompt, options)
11
+ @prompt = prompt
12
+ @options = options
13
+ end
14
+
15
+ def readline
16
+ $stdout.print(prompt)
17
+ get_input
18
+ end
19
+
20
+ private
21
+
22
+ def get_input
23
+ if echo?
24
+ $stdin.gets
25
+ else
26
+ $stdin.noecho(&:gets)
27
+ end
28
+ end
29
+
30
+ def echo?
31
+ options.fetch(:echo, true)
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,88 @@
1
+ begin
2
+ require 'readline'
3
+ rescue LoadError
4
+ end
5
+
6
+ class Thor
7
+ module LineEditor
8
+ class Readline < Basic
9
+ def self.available?
10
+ Object.const_defined?(:Readline)
11
+ end
12
+
13
+ def readline
14
+ if echo?
15
+ ::Readline.completion_append_character = nil
16
+ # Ruby 1.8.7 does not allow Readline.completion_proc= to receive nil.
17
+ if complete = completion_proc
18
+ ::Readline.completion_proc = complete
19
+ end
20
+ ::Readline.readline(prompt, add_to_history?)
21
+ else
22
+ super
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def add_to_history?
29
+ options.fetch(:add_to_history, true)
30
+ end
31
+
32
+ def completion_proc
33
+ if use_path_completion?
34
+ Proc.new { |text| PathCompletion.new(text).matches }
35
+ elsif completion_options.any?
36
+ Proc.new do |text|
37
+ completion_options.select { |option| option.start_with?(text) }
38
+ end
39
+ end
40
+ end
41
+
42
+ def completion_options
43
+ options.fetch(:limited_to, [])
44
+ end
45
+
46
+ def use_path_completion?
47
+ options.fetch(:path, false)
48
+ end
49
+
50
+ class PathCompletion
51
+ attr_reader :text
52
+ private :text
53
+
54
+ def initialize(text)
55
+ @text = text
56
+ end
57
+
58
+ def matches
59
+ relative_matches
60
+ end
61
+
62
+ private
63
+
64
+ def relative_matches
65
+ absolute_matches.map { |path| path.sub(base_path, '') }
66
+ end
67
+
68
+ def absolute_matches
69
+ Dir[glob_pattern].map do |path|
70
+ if File.directory?(path)
71
+ "#{path}/"
72
+ else
73
+ path
74
+ end
75
+ end
76
+ end
77
+
78
+ def glob_pattern
79
+ "#{base_path}#{text}*"
80
+ end
81
+
82
+ def base_path
83
+ "#{Dir.pwd}/"
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1,17 +1,17 @@
1
1
  class Thor
2
2
  class Argument #:nodoc:
3
- VALID_TYPES = [ :numeric, :hash, :array, :string ]
3
+ VALID_TYPES = [:numeric, :hash, :array, :string]
4
4
 
5
5
  attr_reader :name, :description, :enum, :required, :type, :default, :banner
6
- alias :human_name :name
6
+ alias_method :human_name, :name
7
7
 
8
- def initialize(name, options={})
9
- class_name = self.class.name.split("::").last
8
+ def initialize(name, options = {})
9
+ class_name = self.class.name.split('::').last
10
10
 
11
11
  type = options[:type]
12
12
 
13
- raise ArgumentError, "#{class_name} name can't be nil." if name.nil?
14
- raise ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type)
13
+ fail ArgumentError, "#{class_name} name can't be nil." if name.nil?
14
+ fail ArgumentError, "Type :#{type} is not valid for #{class_name.downcase}s." if type && !valid_type?(type)
15
15
 
16
16
  @name = name.to_s
17
17
  @description = options[:desc]
@@ -41,34 +41,33 @@ class Thor
41
41
  end
42
42
  end
43
43
 
44
- protected
44
+ protected
45
45
 
46
- def validate!
47
- if required? && !default.nil?
48
- raise ArgumentError, "An argument cannot be required and have default value."
49
- elsif @enum && !@enum.is_a?(Array)
50
- raise ArgumentError, "An argument cannot have an enum other than an array."
51
- end
46
+ def validate!
47
+ if required? && !default.nil?
48
+ fail ArgumentError, 'An argument cannot be required and have default value.'
49
+ elsif @enum && !@enum.is_a?(Array)
50
+ fail ArgumentError, 'An argument cannot have an enum other than an array.'
52
51
  end
52
+ end
53
53
 
54
- def valid_type?(type)
55
- self.class::VALID_TYPES.include?(type.to_sym)
56
- end
54
+ def valid_type?(type)
55
+ self.class::VALID_TYPES.include?(type.to_sym)
56
+ end
57
57
 
58
- def default_banner
59
- case type
60
- when :boolean
61
- nil
62
- when :string, :default
63
- human_name.upcase
64
- when :numeric
65
- "N"
66
- when :hash
67
- "key:value"
68
- when :array
69
- "one two three"
70
- end
58
+ def default_banner
59
+ case type
60
+ when :boolean
61
+ nil
62
+ when :string, :default
63
+ human_name.upcase
64
+ when :numeric
65
+ 'N'
66
+ when :hash
67
+ 'key:value'
68
+ when :array
69
+ 'one two three'
71
70
  end
72
-
71
+ end
73
72
  end
74
73
  end
@@ -1,5 +1,5 @@
1
1
  class Thor
2
- class Arguments #:nodoc:
2
+ class Arguments #:nodoc: # rubocop:disable ClassLength
3
3
  NUMERIC = /(\d*\.\d+|\d+)/
4
4
 
5
5
  # Receives an array of args and returns two arrays, one with arguments
@@ -13,7 +13,7 @@ class Thor
13
13
  arguments << item
14
14
  end
15
15
 
16
- return arguments, args[Range.new(arguments.size, -1)]
16
+ [arguments, args[Range.new(arguments.size, -1)]]
17
17
  end
18
18
 
19
19
  def self.parse(*args)
@@ -23,12 +23,12 @@ class Thor
23
23
 
24
24
  # Takes an array of Thor::Argument objects.
25
25
  #
26
- def initialize(arguments=[])
26
+ def initialize(arguments = [])
27
27
  @assigns, @non_assigned_required = {}, []
28
28
  @switches = arguments
29
29
 
30
30
  arguments.each do |argument|
31
- if argument.default != nil
31
+ if !argument.default.nil?
32
32
  @assigns[argument.human_name] = argument.default
33
33
  elsif argument.required?
34
34
  @non_assigned_required << argument
@@ -49,123 +49,127 @@ class Thor
49
49
  @assigns
50
50
  end
51
51
 
52
- def remaining
52
+ def remaining # rubocop:disable TrivialAccessors
53
53
  @pile
54
54
  end
55
55
 
56
- private
56
+ private
57
57
 
58
- def no_or_skip?(arg)
59
- arg =~ /^--(no|skip)-([-\w]+)$/
60
- $2
61
- end
58
+ def no_or_skip?(arg)
59
+ arg =~ /^--(no|skip)-([-\w]+)$/
60
+ $2
61
+ end
62
62
 
63
- def last?
64
- @pile.empty?
65
- end
63
+ def last?
64
+ @pile.empty?
65
+ end
66
66
 
67
- def peek
68
- @pile.first
69
- end
67
+ def peek
68
+ @pile.first
69
+ end
70
70
 
71
- def shift
72
- @pile.shift
73
- end
71
+ def shift
72
+ @pile.shift
73
+ end
74
74
 
75
- def unshift(arg)
76
- unless arg.kind_of?(Array)
77
- @pile.unshift(arg)
78
- else
79
- @pile = arg + @pile
80
- end
75
+ def unshift(arg)
76
+ if arg.kind_of?(Array)
77
+ @pile = arg + @pile
78
+ else
79
+ @pile.unshift(arg)
81
80
  end
81
+ end
82
82
 
83
- def current_is_value?
84
- peek && peek.to_s !~ /^-/
85
- end
83
+ def current_is_value?
84
+ peek && peek.to_s !~ /^-/
85
+ end
86
86
 
87
- # Runs through the argument array getting strings that contains ":" and
88
- # mark it as a hash:
89
- #
90
- # [ "name:string", "age:integer" ]
91
- #
92
- # Becomes:
93
- #
94
- # { "name" => "string", "age" => "integer" }
95
- #
96
- def parse_hash(name)
97
- return shift if peek.is_a?(Hash)
98
- hash = {}
99
-
100
- while current_is_value? && peek.include?(?:)
101
- key, value = shift.split(':',2)
102
- hash[key] = value
103
- end
104
- hash
105
- end
87
+ # Runs through the argument array getting strings that contains ":" and
88
+ # mark it as a hash:
89
+ #
90
+ # [ "name:string", "age:integer" ]
91
+ #
92
+ # Becomes:
93
+ #
94
+ # { "name" => "string", "age" => "integer" }
95
+ #
96
+ def parse_hash(name)
97
+ return shift if peek.is_a?(Hash)
98
+ hash = {}
106
99
 
107
- # Runs through the argument array getting all strings until no string is
108
- # found or a switch is found.
109
- #
110
- # ["a", "b", "c"]
111
- #
112
- # And returns it as an array:
113
- #
114
- # ["a", "b", "c"]
115
- #
116
- def parse_array(name)
117
- return shift if peek.is_a?(Array)
118
- array = []
119
-
120
- while current_is_value?
121
- array << shift
122
- end
123
- array
100
+ while current_is_value? && peek.include?(':')
101
+ key, value = shift.split(':', 2)
102
+ hash[key] = value
124
103
  end
104
+ hash
105
+ end
125
106
 
126
- # Check if the peek is numeric format and return a Float or Integer.
127
- # Otherwise raises an error.
128
- #
129
- def parse_numeric(name)
130
- return shift if peek.is_a?(Numeric)
107
+ # Runs through the argument array getting all strings until no string is
108
+ # found or a switch is found.
109
+ #
110
+ # ["a", "b", "c"]
111
+ #
112
+ # And returns it as an array:
113
+ #
114
+ # ["a", "b", "c"]
115
+ #
116
+ def parse_array(name)
117
+ return shift if peek.is_a?(Array)
118
+ array = []
119
+ array << shift while current_is_value?
120
+ array
121
+ end
131
122
 
132
- unless peek =~ NUMERIC && $& == peek
133
- raise MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}"
134
- end
123
+ # Check if the peek is numeric format and return a Float or Integer.
124
+ # Check if the peek is included in enum if enum is provided.
125
+ # Otherwise raises an error.
126
+ #
127
+ def parse_numeric(name)
128
+ return shift if peek.is_a?(Numeric)
135
129
 
136
- $&.index('.') ? shift.to_f : shift.to_i
130
+ unless peek =~ NUMERIC && $& == peek
131
+ fail MalformattedArgumentError, "Expected numeric value for '#{name}'; got #{peek.inspect}"
137
132
  end
138
133
 
139
- # Parse string:
140
- # for --string-arg, just return the current value in the pile
141
- # for --no-string-arg, nil
142
- #
143
- def parse_string(name)
144
- if no_or_skip?(name)
145
- nil
146
- else
147
- value = shift
148
- if @switches.is_a?(Hash) && switch = @switches[name]
149
- if switch.enum && !switch.enum.include?(value)
150
- raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
151
- end
134
+ value = $&.index('.') ? shift.to_f : shift.to_i
135
+ if @switches.is_a?(Hash) && switch = @switches[name]
136
+ if switch.enum && !switch.enum.include?(value)
137
+ raise MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
152
138
  end
153
- value
154
139
  end
155
- end
156
-
157
- # Raises an error if @non_assigned_required array is not empty.
158
- #
159
- def check_requirement!
160
- unless @non_assigned_required.empty?
161
- names = @non_assigned_required.map do |o|
162
- o.respond_to?(:switch_name) ? o.switch_name : o.human_name
163
- end.join("', '")
140
+ value
141
+ end
164
142
 
165
- class_name = self.class.name.split('::').last.downcase
166
- raise RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'"
143
+ # Parse string:
144
+ # for --string-arg, just return the current value in the pile
145
+ # for --no-string-arg, nil
146
+ # Check if the peek is included in enum if enum is provided. Otherwise raises an error.
147
+ #
148
+ def parse_string(name)
149
+ if no_or_skip?(name)
150
+ nil
151
+ else
152
+ value = shift
153
+ if @switches.is_a?(Hash) && switch = @switches[name] # rubocop:disable AssignmentInCondition
154
+ if switch.enum && !switch.enum.include?(value)
155
+ fail MalformattedArgumentError, "Expected '#{name}' to be one of #{switch.enum.join(', ')}; got #{value}"
156
+ end
167
157
  end
158
+ value
168
159
  end
160
+ end
169
161
 
162
+ # Raises an error if @non_assigned_required array is not empty.
163
+ #
164
+ def check_requirement!
165
+ unless @non_assigned_required.empty?
166
+ names = @non_assigned_required.map do |o|
167
+ o.respond_to?(:switch_name) ? o.switch_name : o.human_name
168
+ end.join("', '")
169
+
170
+ class_name = self.class.name.split('::').last.downcase
171
+ fail RequiredArgumentMissingError, "No value provided for required #{class_name} '#{names}'"
172
+ end
173
+ end
170
174
  end
171
175
  end