bundler 0.8.1 → 0.9.0.pre1

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/README +7 -0
  2. data/bin/bundle +3 -0
  3. data/lib/bundler.rb +72 -37
  4. data/lib/bundler/cli.rb +64 -68
  5. data/lib/bundler/definition.rb +78 -0
  6. data/lib/bundler/dependency.rb +7 -57
  7. data/lib/bundler/dsl.rb +42 -142
  8. data/lib/bundler/environment.rb +94 -54
  9. data/lib/bundler/index.rb +98 -0
  10. data/lib/bundler/installer.rb +137 -0
  11. data/lib/bundler/remote_specification.rb +1 -1
  12. data/lib/bundler/resolver.rb +20 -50
  13. data/lib/bundler/rubygems.rb +22 -0
  14. data/lib/bundler/source.rb +185 -295
  15. data/lib/bundler/specification.rb +22 -0
  16. data/lib/bundler/templates/Gemfile +4 -0
  17. data/lib/bundler/templates/environment.erb +3 -153
  18. data/lib/bundler/ui.rb +51 -0
  19. data/lib/bundler/vendor/thor.rb +241 -0
  20. data/lib/bundler/vendor/thor/actions.rb +274 -0
  21. data/lib/bundler/vendor/thor/actions/create_file.rb +103 -0
  22. data/lib/bundler/vendor/thor/actions/directory.rb +91 -0
  23. data/lib/bundler/vendor/thor/actions/empty_directory.rb +134 -0
  24. data/lib/bundler/vendor/thor/actions/file_manipulation.rb +223 -0
  25. data/lib/bundler/vendor/thor/actions/inject_into_file.rb +101 -0
  26. data/lib/bundler/vendor/thor/base.rb +515 -0
  27. data/lib/bundler/vendor/thor/core_ext/file_binary_read.rb +9 -0
  28. data/lib/bundler/vendor/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  29. data/lib/bundler/vendor/thor/core_ext/ordered_hash.rb +100 -0
  30. data/lib/bundler/vendor/thor/error.rb +27 -0
  31. data/lib/bundler/vendor/thor/group.rb +267 -0
  32. data/lib/bundler/vendor/thor/invocation.rb +178 -0
  33. data/lib/bundler/vendor/thor/parser.rb +4 -0
  34. data/lib/bundler/vendor/thor/parser/argument.rb +67 -0
  35. data/lib/bundler/vendor/thor/parser/arguments.rb +145 -0
  36. data/lib/bundler/vendor/thor/parser/option.rb +132 -0
  37. data/lib/bundler/vendor/thor/parser/options.rb +142 -0
  38. data/lib/bundler/vendor/thor/rake_compat.rb +66 -0
  39. data/lib/bundler/vendor/thor/runner.rb +303 -0
  40. data/lib/bundler/vendor/thor/shell.rb +78 -0
  41. data/lib/bundler/vendor/thor/shell/basic.rb +239 -0
  42. data/lib/bundler/vendor/thor/shell/color.rb +108 -0
  43. data/lib/bundler/vendor/thor/task.rb +111 -0
  44. data/lib/bundler/vendor/thor/util.rb +233 -0
  45. data/lib/bundler/vendor/thor/version.rb +3 -0
  46. metadata +48 -26
  47. data/README.markdown +0 -284
  48. data/Rakefile +0 -81
  49. data/lib/bundler/bundle.rb +0 -314
  50. data/lib/bundler/commands/bundle_command.rb +0 -72
  51. data/lib/bundler/commands/exec_command.rb +0 -36
  52. data/lib/bundler/finder.rb +0 -51
  53. data/lib/bundler/gem_bundle.rb +0 -11
  54. data/lib/bundler/gem_ext.rb +0 -34
  55. data/lib/bundler/runtime.rb +0 -2
  56. data/lib/bundler/templates/app_script.erb +0 -3
  57. data/lib/bundler/templates/environment_picker.erb +0 -4
  58. data/lib/rubygems_plugin.rb +0 -6
@@ -0,0 +1,78 @@
1
+ require 'rbconfig'
2
+ require 'thor/shell/color'
3
+
4
+ class Thor
5
+ module Base
6
+ # Returns the shell used in all Thor classes. If you are in a Unix platform
7
+ # it will use a colored log, otherwise it will use a basic one without color.
8
+ #
9
+ def self.shell
10
+ @shell ||= if Config::CONFIG['host_os'] =~ /mswin|mingw/
11
+ Thor::Shell::Basic
12
+ else
13
+ Thor::Shell::Color
14
+ end
15
+ end
16
+
17
+ # Sets the shell used in all Thor classes.
18
+ #
19
+ def self.shell=(klass)
20
+ @shell = klass
21
+ end
22
+ end
23
+
24
+ module Shell
25
+ SHELL_DELEGATED_METHODS = [:ask, :yes?, :no?, :say, :say_status, :print_table]
26
+
27
+ # Add shell to initialize config values.
28
+ #
29
+ # ==== Configuration
30
+ # shell<Object>:: An instance of the shell to be used.
31
+ #
32
+ # ==== Examples
33
+ #
34
+ # class MyScript < Thor
35
+ # argument :first, :type => :numeric
36
+ # end
37
+ #
38
+ # MyScript.new [1.0], { :foo => :bar }, :shell => Thor::Shell::Basic.new
39
+ #
40
+ def initialize(args=[], options={}, config={})
41
+ super
42
+ self.shell = config[:shell]
43
+ self.shell.base ||= self if self.shell.respond_to?(:base)
44
+ end
45
+
46
+ # Holds the shell for the given Thor instance. If no shell is given,
47
+ # it gets a default shell from Thor::Base.shell.
48
+ #
49
+ def shell
50
+ @shell ||= Thor::Base.shell.new
51
+ end
52
+
53
+ # Sets the shell for this thor class.
54
+ #
55
+ def shell=(shell)
56
+ @shell = shell
57
+ end
58
+
59
+ # Common methods that are delegated to the shell.
60
+ #
61
+ SHELL_DELEGATED_METHODS.each do |method|
62
+ module_eval <<-METHOD, __FILE__, __LINE__
63
+ def #{method}(*args)
64
+ shell.#{method}(*args)
65
+ end
66
+ METHOD
67
+ end
68
+
69
+ protected
70
+
71
+ # Allow shell to be shared between invocations.
72
+ #
73
+ def _shared_configuration #:nodoc:
74
+ super.merge!(:shell => self.shell)
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,239 @@
1
+ require 'tempfile'
2
+
3
+ class Thor
4
+ module Shell
5
+ class Basic
6
+ attr_accessor :base, :padding
7
+
8
+ # Initialize base and padding to nil.
9
+ #
10
+ def initialize #:nodoc:
11
+ @base, @padding = nil, 0
12
+ end
13
+
14
+ # Sets the output padding, not allowing less than zero values.
15
+ #
16
+ def padding=(value)
17
+ @padding = [0, value].max
18
+ end
19
+
20
+ # Ask something to the user and receives a response.
21
+ #
22
+ # ==== Example
23
+ # ask("What is your name?")
24
+ #
25
+ def ask(statement, color=nil)
26
+ say("#{statement} ", color)
27
+ $stdin.gets.strip
28
+ end
29
+
30
+ # Say (print) something to the user. If the sentence ends with a whitespace
31
+ # or tab character, a new line is not appended (print + flush). Otherwise
32
+ # are passed straight to puts (behavior got from Highline).
33
+ #
34
+ # ==== Example
35
+ # say("I know you knew that.")
36
+ #
37
+ def say(message="", color=nil, force_new_line=(message.to_s !~ /( |\t)$/))
38
+ message = message.to_s
39
+ message = set_color(message, color) if color
40
+
41
+ if force_new_line
42
+ $stdout.puts(message)
43
+ else
44
+ $stdout.print(message)
45
+ $stdout.flush
46
+ end
47
+ end
48
+
49
+ # Say a status with the given color and appends the message. Since this
50
+ # method is used frequently by actions, it allows nil or false to be given
51
+ # in log_status, avoiding the message from being shown. If a Symbol is
52
+ # given in log_status, it's used as the color.
53
+ #
54
+ def say_status(status, message, log_status=true)
55
+ return if quiet? || log_status == false
56
+ spaces = " " * (padding + 1)
57
+ color = log_status.is_a?(Symbol) ? log_status : :green
58
+
59
+ status = status.to_s.rjust(12)
60
+ status = set_color status, color, true if color
61
+ say "#{status}#{spaces}#{message}", nil, true
62
+ end
63
+
64
+ # Make a question the to user and returns true if the user replies "y" or
65
+ # "yes".
66
+ #
67
+ def yes?(statement, color=nil)
68
+ ask(statement, color) =~ is?(:yes)
69
+ end
70
+
71
+ # Make a question the to user and returns true if the user replies "n" or
72
+ # "no".
73
+ #
74
+ def no?(statement, color=nil)
75
+ !yes?(statement, color)
76
+ end
77
+
78
+ # Prints a table.
79
+ #
80
+ # ==== Parameters
81
+ # Array[Array[String, String, ...]]
82
+ #
83
+ # ==== Options
84
+ # ident<Integer>:: Ident the first column by ident value.
85
+ #
86
+ def print_table(table, options={})
87
+ return if table.empty?
88
+
89
+ formats, ident = [], options[:ident].to_i
90
+ options[:truncate] = terminal_width if options[:truncate] == true
91
+
92
+ 0.upto(table.first.length - 2) do |i|
93
+ maxima = table.max{ |a,b| a[i].size <=> b[i].size }[i].size
94
+ formats << "%-#{maxima + 2}s"
95
+ end
96
+
97
+ formats[0] = formats[0].insert(0, " " * ident)
98
+ formats << "%s"
99
+
100
+ table.each do |row|
101
+ sentence = ""
102
+
103
+ row.each_with_index do |column, i|
104
+ sentence << formats[i] % column.to_s
105
+ end
106
+
107
+ sentence = truncate(sentence, options[:truncate]) if options[:truncate]
108
+ $stdout.puts sentence
109
+ end
110
+ end
111
+
112
+ # Deals with file collision and returns true if the file should be
113
+ # overwriten and false otherwise. If a block is given, it uses the block
114
+ # response as the content for the diff.
115
+ #
116
+ # ==== Parameters
117
+ # destination<String>:: the destination file to solve conflicts
118
+ # block<Proc>:: an optional block that returns the value to be used in diff
119
+ #
120
+ def file_collision(destination)
121
+ return true if @always_force
122
+ options = block_given? ? "[Ynaqdh]" : "[Ynaqh]"
123
+
124
+ while true
125
+ answer = ask %[Overwrite #{destination}? (enter "h" for help) #{options}]
126
+
127
+ case answer
128
+ when is?(:yes), is?(:force), ""
129
+ return true
130
+ when is?(:no), is?(:skip)
131
+ return false
132
+ when is?(:always)
133
+ return @always_force = true
134
+ when is?(:quit)
135
+ say 'Aborting...'
136
+ raise SystemExit
137
+ when is?(:diff)
138
+ show_diff(destination, yield) if block_given?
139
+ say 'Retrying...'
140
+ else
141
+ say file_collision_help
142
+ end
143
+ end
144
+ end
145
+
146
+ # Called if something goes wrong during the execution. This is used by Thor
147
+ # internally and should not be used inside your scripts. If someone went
148
+ # wrong, you can always raise an exception. If you raise a Thor::Error, it
149
+ # will be rescued and wrapped in the method below.
150
+ #
151
+ def error(statement)
152
+ $stderr.puts statement
153
+ end
154
+
155
+ # Apply color to the given string with optional bold. Disabled in the
156
+ # Thor::Shell::Basic class.
157
+ #
158
+ def set_color(string, color, bold=false) #:nodoc:
159
+ string
160
+ end
161
+
162
+ protected
163
+
164
+ def is?(value) #:nodoc:
165
+ value = value.to_s
166
+
167
+ if value.size == 1
168
+ /\A#{value}\z/i
169
+ else
170
+ /\A(#{value}|#{value[0,1]})\z/i
171
+ end
172
+ end
173
+
174
+ def file_collision_help #:nodoc:
175
+ <<HELP
176
+ Y - yes, overwrite
177
+ n - no, do not overwrite
178
+ a - all, overwrite this and all others
179
+ q - quit, abort
180
+ d - diff, show the differences between the old and the new
181
+ h - help, show this help
182
+ HELP
183
+ end
184
+
185
+ def show_diff(destination, content) #:nodoc:
186
+ diff_cmd = ENV['THOR_DIFF'] || ENV['RAILS_DIFF'] || 'diff -u'
187
+
188
+ Tempfile.open(File.basename(destination), File.dirname(destination)) do |temp|
189
+ temp.write content
190
+ temp.rewind
191
+ system %(#{diff_cmd} "#{destination}" "#{temp.path}")
192
+ end
193
+ end
194
+
195
+ def quiet? #:nodoc:
196
+ base && base.options[:quiet]
197
+ end
198
+
199
+ # This code was copied from Rake, available under MIT-LICENSE
200
+ # Copyright (c) 2003, 2004 Jim Weirich
201
+ def terminal_width
202
+ if ENV['THOR_COLUMNS']
203
+ result = ENV['THOR_COLUMNS'].to_i
204
+ else
205
+ result = unix? ? dynamic_width : 80
206
+ end
207
+ (result < 10) ? 80 : result
208
+ rescue
209
+ 80
210
+ end
211
+
212
+ # Calculate the dynamic width of the terminal
213
+ def dynamic_width
214
+ @dynamic_width ||= (dynamic_width_stty.nonzero? || dynamic_width_tput)
215
+ end
216
+
217
+ def dynamic_width_stty
218
+ %x{stty size 2>/dev/null}.split[1].to_i
219
+ end
220
+
221
+ def dynamic_width_tput
222
+ %x{tput cols 2>/dev/null}.to_i
223
+ end
224
+
225
+ def unix?
226
+ RUBY_PLATFORM =~ /(aix|darwin|linux|(net|free|open)bsd|cygwin|solaris|irix|hpux)/i
227
+ end
228
+
229
+ def truncate(string, width)
230
+ if string.length <= width
231
+ string
232
+ else
233
+ ( string[0, width-3] || "" ) + "..."
234
+ end
235
+ end
236
+
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,108 @@
1
+ require 'thor/shell/basic'
2
+
3
+ class Thor
4
+ module Shell
5
+ # Inherit from Thor::Shell::Basic and add set_color behavior. Check
6
+ # Thor::Shell::Basic to see all available methods.
7
+ #
8
+ class Color < Basic
9
+ # Embed in a String to clear all previous ANSI sequences.
10
+ CLEAR = "\e[0m"
11
+ # The start of an ANSI bold sequence.
12
+ BOLD = "\e[1m"
13
+
14
+ # Set the terminal's foreground ANSI color to black.
15
+ BLACK = "\e[30m"
16
+ # Set the terminal's foreground ANSI color to red.
17
+ RED = "\e[31m"
18
+ # Set the terminal's foreground ANSI color to green.
19
+ GREEN = "\e[32m"
20
+ # Set the terminal's foreground ANSI color to yellow.
21
+ YELLOW = "\e[33m"
22
+ # Set the terminal's foreground ANSI color to blue.
23
+ BLUE = "\e[34m"
24
+ # Set the terminal's foreground ANSI color to magenta.
25
+ MAGENTA = "\e[35m"
26
+ # Set the terminal's foreground ANSI color to cyan.
27
+ CYAN = "\e[36m"
28
+ # Set the terminal's foreground ANSI color to white.
29
+ WHITE = "\e[37m"
30
+
31
+ # Set the terminal's background ANSI color to black.
32
+ ON_BLACK = "\e[40m"
33
+ # Set the terminal's background ANSI color to red.
34
+ ON_RED = "\e[41m"
35
+ # Set the terminal's background ANSI color to green.
36
+ ON_GREEN = "\e[42m"
37
+ # Set the terminal's background ANSI color to yellow.
38
+ ON_YELLOW = "\e[43m"
39
+ # Set the terminal's background ANSI color to blue.
40
+ ON_BLUE = "\e[44m"
41
+ # Set the terminal's background ANSI color to magenta.
42
+ ON_MAGENTA = "\e[45m"
43
+ # Set the terminal's background ANSI color to cyan.
44
+ ON_CYAN = "\e[46m"
45
+ # Set the terminal's background ANSI color to white.
46
+ ON_WHITE = "\e[47m"
47
+
48
+ # Set color by using a string or one of the defined constants. If a third
49
+ # option is set to true, it also adds bold to the string. This is based
50
+ # on Highline implementation and it automatically appends CLEAR to the end
51
+ # of the returned String.
52
+ #
53
+ def set_color(string, color, bold=false)
54
+ color = self.class.const_get(color.to_s.upcase) if color.is_a?(Symbol)
55
+ bold = bold ? BOLD : ""
56
+ "#{bold}#{color}#{string}#{CLEAR}"
57
+ end
58
+
59
+ protected
60
+
61
+ # Overwrite show_diff to show diff with colors if Diff::LCS is
62
+ # available.
63
+ #
64
+ def show_diff(destination, content) #:nodoc:
65
+ if diff_lcs_loaded? && ENV['THOR_DIFF'].nil? && ENV['RAILS_DIFF'].nil?
66
+ actual = File.binread(destination).to_s.split("\n")
67
+ content = content.to_s.split("\n")
68
+
69
+ Diff::LCS.sdiff(actual, content).each do |diff|
70
+ output_diff_line(diff)
71
+ end
72
+ else
73
+ super
74
+ end
75
+ end
76
+
77
+ def output_diff_line(diff) #:nodoc:
78
+ case diff.action
79
+ when '-'
80
+ say "- #{diff.old_element.chomp}", :red, true
81
+ when '+'
82
+ say "+ #{diff.new_element.chomp}", :green, true
83
+ when '!'
84
+ say "- #{diff.old_element.chomp}", :red, true
85
+ say "+ #{diff.new_element.chomp}", :green, true
86
+ else
87
+ say " #{diff.old_element.chomp}", nil, true
88
+ end
89
+ end
90
+
91
+ # Check if Diff::LCS is loaded. If it is, use it to create pretty output
92
+ # for diff.
93
+ #
94
+ def diff_lcs_loaded? #:nodoc:
95
+ return true if defined?(Diff::LCS)
96
+ return @diff_lcs_loaded unless @diff_lcs_loaded.nil?
97
+
98
+ @diff_lcs_loaded = begin
99
+ require 'diff/lcs'
100
+ true
101
+ rescue LoadError
102
+ false
103
+ end
104
+ end
105
+
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,111 @@
1
+ class Thor
2
+ class Task < Struct.new(:name, :description, :usage, :options)
3
+ FILE_REGEXP = /^#{Regexp.escape(File.expand_path(__FILE__))}:[\w:]+ `run'$/
4
+
5
+ # A dynamic task that handles method missing scenarios.
6
+ class Dynamic < Task
7
+ def initialize(name, options=nil)
8
+ super(name.to_s, "A dynamically-generated task", name.to_s, options)
9
+ end
10
+
11
+ def run(instance, args=[])
12
+ unless (instance.methods & [name.to_s, name.to_sym]).empty?
13
+ raise Error, "could not find Thor class or task '#{name}'"
14
+ end
15
+ super
16
+ end
17
+ end
18
+
19
+ def initialize(name, description, usage, options=nil)
20
+ super(name.to_s, description, usage, options || {})
21
+ end
22
+
23
+ def initialize_copy(other) #:nodoc:
24
+ super(other)
25
+ self.options = other.options.dup if other.options
26
+ end
27
+
28
+ # By default, a task invokes a method in the thor class. You can change this
29
+ # implementation to create custom tasks.
30
+ def run(instance, args=[])
31
+ raise UndefinedTaskError, "the '#{name}' task of #{instance.class} is private" unless public_method?(instance)
32
+ instance.send(name, *args)
33
+ rescue ArgumentError => e
34
+ raise e if instance.class.respond_to?(:debugging) && instance.class.debugging
35
+ parse_argument_error(instance, e, caller)
36
+ rescue NoMethodError => e
37
+ raise e if instance.class.respond_to?(:debugging) && instance.class.debugging
38
+ parse_no_method_error(instance, e)
39
+ end
40
+
41
+ # Returns the formatted usage by injecting given required arguments
42
+ # and required options into the given usage.
43
+ def formatted_usage(klass, namespace=nil)
44
+ namespace = klass.namespace if namespace.nil?
45
+
46
+ # Add namespace
47
+ formatted = if namespace
48
+ "#{namespace.gsub(/^(default|thor:runner:)/,'')}:"
49
+ else
50
+ ""
51
+ end
52
+
53
+ # Add usage with required arguments
54
+ formatted << if klass && !klass.arguments.empty?
55
+ usage.to_s.gsub(/^#{name}/) do |match|
56
+ match << " " << klass.arguments.map{ |a| a.usage }.compact.join(' ')
57
+ end
58
+ else
59
+ usage.to_s
60
+ end
61
+
62
+ # Add required options
63
+ formatted << " #{required_options}"
64
+
65
+ # Strip and go!
66
+ formatted.strip
67
+ end
68
+
69
+ protected
70
+
71
+ def required_options
72
+ @required_options ||= options.map{ |_, o| o.usage if o.required? }.compact.sort.join(" ")
73
+ end
74
+
75
+ # Given a target, checks if this class name is not a private/protected method.
76
+ def public_method?(instance) #:nodoc:
77
+ collection = instance.private_methods + instance.protected_methods
78
+ (collection & [name.to_s, name.to_sym]).empty?
79
+ end
80
+
81
+ # For Ruby <= 1.8.7, we have to match the method name that we are trying to call.
82
+ # In Ruby >= 1.9.1, we have to match the method run in this file.
83
+ def backtrace_match?(backtrace) #:nodoc:
84
+ method_name = /`#{Regexp.escape(name.split(':').last)}'/
85
+ backtrace =~ method_name || backtrace =~ FILE_REGEXP
86
+ end
87
+
88
+ def parse_argument_error(instance, e, caller) #:nodoc:
89
+ if e.message =~ /wrong number of arguments/ && backtrace_match?(e.backtrace.first.to_s)
90
+ if instance.is_a?(Thor::Group)
91
+ raise e, "'#{name}' was called incorrectly. Are you sure it has arity equals to 0?"
92
+ else
93
+ raise InvocationError, "'#{name}' was called incorrectly. Call as " <<
94
+ "'#{formatted_usage(instance.class)}'"
95
+ end
96
+ else
97
+ raise e
98
+ end
99
+ end
100
+
101
+ def parse_no_method_error(instance, e) #:nodoc:
102
+ if e.message =~ /^undefined method `#{name}' for #{Regexp.escape(instance.to_s)}$/
103
+ raise UndefinedTaskError, "The #{instance.class.namespace} namespace " <<
104
+ "doesn't have a '#{name}' task"
105
+ else
106
+ raise e
107
+ end
108
+ end
109
+
110
+ end
111
+ end