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,274 @@
1
+ require 'fileutils'
2
+ require 'thor/core_ext/file_binary_read'
3
+
4
+ Dir[File.join(File.dirname(__FILE__), "actions", "*.rb")].each do |action|
5
+ require action
6
+ end
7
+
8
+ class Thor
9
+ module Actions
10
+ attr_accessor :behavior
11
+
12
+ def self.included(base) #:nodoc:
13
+ base.extend ClassMethods
14
+ end
15
+
16
+ module ClassMethods
17
+ # Hold source paths for one Thor instance. source_paths_for_search is the
18
+ # method responsible to gather source_paths from this current class,
19
+ # inherited paths and the source root.
20
+ #
21
+ def source_paths
22
+ @source_paths ||= []
23
+ end
24
+
25
+ # Returns the source paths in the following order:
26
+ #
27
+ # 1) This class source paths
28
+ # 2) Source root
29
+ # 3) Parents source paths
30
+ #
31
+ def source_paths_for_search
32
+ paths = []
33
+ paths += self.source_paths
34
+ paths << self.source_root if self.respond_to?(:source_root)
35
+ paths += from_superclass(:source_paths, [])
36
+ paths
37
+ end
38
+
39
+ # Add runtime options that help actions execution.
40
+ #
41
+ def add_runtime_options!
42
+ class_option :force, :type => :boolean, :aliases => "-f", :group => :runtime,
43
+ :desc => "Overwrite files that already exist"
44
+
45
+ class_option :pretend, :type => :boolean, :aliases => "-p", :group => :runtime,
46
+ :desc => "Run but do not make any changes"
47
+
48
+ class_option :quiet, :type => :boolean, :aliases => "-q", :group => :runtime,
49
+ :desc => "Supress status output"
50
+
51
+ class_option :skip, :type => :boolean, :aliases => "-s", :group => :runtime,
52
+ :desc => "Skip files that already exist"
53
+ end
54
+ end
55
+
56
+ # Extends initializer to add more configuration options.
57
+ #
58
+ # ==== Configuration
59
+ # behavior<Symbol>:: The actions default behavior. Can be :invoke or :revoke.
60
+ # It also accepts :force, :skip and :pretend to set the behavior
61
+ # and the respective option.
62
+ #
63
+ # destination_root<String>:: The root directory needed for some actions.
64
+ #
65
+ def initialize(args=[], options={}, config={})
66
+ self.behavior = case config[:behavior].to_s
67
+ when "force", "skip"
68
+ _cleanup_options_and_set(options, config[:behavior])
69
+ :invoke
70
+ when "revoke"
71
+ :revoke
72
+ else
73
+ :invoke
74
+ end
75
+
76
+ super
77
+ self.destination_root = config[:destination_root]
78
+ end
79
+
80
+ # Wraps an action object and call it accordingly to the thor class behavior.
81
+ #
82
+ def action(instance) #:nodoc:
83
+ if behavior == :revoke
84
+ instance.revoke!
85
+ else
86
+ instance.invoke!
87
+ end
88
+ end
89
+
90
+ # Returns the root for this thor class (also aliased as destination root).
91
+ #
92
+ def destination_root
93
+ @destination_stack.last
94
+ end
95
+
96
+ # Sets the root for this thor class. Relatives path are added to the
97
+ # directory where the script was invoked and expanded.
98
+ #
99
+ def destination_root=(root)
100
+ @destination_stack ||= []
101
+ @destination_stack[0] = File.expand_path(root || '')
102
+ end
103
+
104
+ # Returns the given path relative to the absolute root (ie, root where
105
+ # the script started).
106
+ #
107
+ def relative_to_original_destination_root(path, remove_dot=true)
108
+ path = path.gsub(@destination_stack[0], '.')
109
+ remove_dot ? (path[2..-1] || '') : path
110
+ end
111
+
112
+ # Holds source paths in instance so they can be manipulated.
113
+ #
114
+ def source_paths
115
+ @source_paths ||= self.class.source_paths_for_search
116
+ end
117
+
118
+ # Receives a file or directory and search for it in the source paths.
119
+ #
120
+ def find_in_source_paths(file)
121
+ relative_root = relative_to_original_destination_root(destination_root, false)
122
+
123
+ source_paths.each do |source|
124
+ source_file = File.expand_path(file, File.join(source, relative_root))
125
+ return source_file if File.exists?(source_file)
126
+ end
127
+
128
+ if source_paths.empty?
129
+ raise Error, "You don't have any source path defined for class #{self.class.name}. To fix this, " <<
130
+ "you can define a source_root in your class."
131
+ else
132
+ raise Error, "Could not find #{file.inspect} in source paths."
133
+ end
134
+ end
135
+
136
+ # Do something in the root or on a provided subfolder. If a relative path
137
+ # is given it's referenced from the current root. The full path is yielded
138
+ # to the block you provide. The path is set back to the previous path when
139
+ # the method exits.
140
+ #
141
+ # ==== Parameters
142
+ # dir<String>:: the directory to move to.
143
+ # config<Hash>:: give :verbose => true to log and use padding.
144
+ #
145
+ def inside(dir='', config={}, &block)
146
+ verbose = config.fetch(:verbose, false)
147
+
148
+ say_status :inside, dir, verbose
149
+ shell.padding += 1 if verbose
150
+ @destination_stack.push File.expand_path(dir, destination_root)
151
+
152
+ FileUtils.mkdir_p(destination_root) unless File.exist?(destination_root)
153
+ FileUtils.cd(destination_root) { block.arity == 1 ? yield(destination_root) : yield }
154
+
155
+ @destination_stack.pop
156
+ shell.padding -= 1 if verbose
157
+ end
158
+
159
+ # Goes to the root and execute the given block.
160
+ #
161
+ def in_root
162
+ inside(@destination_stack.first) { yield }
163
+ end
164
+
165
+ # Loads an external file and execute it in the instance binding.
166
+ #
167
+ # ==== Parameters
168
+ # path<String>:: The path to the file to execute. Can be a web address or
169
+ # a relative path from the source root.
170
+ #
171
+ # ==== Examples
172
+ #
173
+ # apply "http://gist.github.com/103208"
174
+ #
175
+ # apply "recipes/jquery.rb"
176
+ #
177
+ def apply(path, config={})
178
+ verbose = config.fetch(:verbose, true)
179
+ path = find_in_source_paths(path) unless path =~ /^http\:\/\//
180
+
181
+ say_status :apply, path, verbose
182
+ shell.padding += 1 if verbose
183
+ instance_eval(open(path).read)
184
+ shell.padding -= 1 if verbose
185
+ end
186
+
187
+ # Executes a command.
188
+ #
189
+ # ==== Parameters
190
+ # command<String>:: the command to be executed.
191
+ # config<Hash>:: give :verbose => false to not log the status. Specify :with
192
+ # to append an executable to command executation.
193
+ #
194
+ # ==== Example
195
+ #
196
+ # inside('vendor') do
197
+ # run('ln -s ~/edge rails')
198
+ # end
199
+ #
200
+ def run(command, config={})
201
+ return unless behavior == :invoke
202
+
203
+ destination = relative_to_original_destination_root(destination_root, false)
204
+ desc = "#{command} from #{destination.inspect}"
205
+
206
+ if config[:with]
207
+ desc = "#{File.basename(config[:with].to_s)} #{desc}"
208
+ command = "#{config[:with]} #{command}"
209
+ end
210
+
211
+ say_status :run, desc, config.fetch(:verbose, true)
212
+ system(command) unless options[:pretend]
213
+ end
214
+
215
+ # Executes a ruby script (taking into account WIN32 platform quirks).
216
+ #
217
+ # ==== Parameters
218
+ # command<String>:: the command to be executed.
219
+ # config<Hash>:: give :verbose => false to not log the status.
220
+ #
221
+ def run_ruby_script(command, config={})
222
+ return unless behavior == :invoke
223
+ run "#{command}", config.merge(:with => Thor::Util.ruby_command)
224
+ end
225
+
226
+ # Run a thor command. A hash of options can be given and it's converted to
227
+ # switches.
228
+ #
229
+ # ==== Parameters
230
+ # task<String>:: the task to be invoked
231
+ # args<Array>:: arguments to the task
232
+ # config<Hash>:: give :verbose => false to not log the status. Other options
233
+ # are given as parameter to Thor.
234
+ #
235
+ # ==== Examples
236
+ #
237
+ # thor :install, "http://gist.github.com/103208"
238
+ # #=> thor install http://gist.github.com/103208
239
+ #
240
+ # thor :list, :all => true, :substring => 'rails'
241
+ # #=> thor list --all --substring=rails
242
+ #
243
+ def thor(task, *args)
244
+ config = args.last.is_a?(Hash) ? args.pop : {}
245
+ verbose = config.key?(:verbose) ? config.delete(:verbose) : true
246
+
247
+ args.unshift task
248
+ args.push Thor::Options.to_switches(config)
249
+ command = args.join(' ').strip
250
+
251
+ run command, :with => :thor, :verbose => verbose
252
+ end
253
+
254
+ protected
255
+
256
+ # Allow current root to be shared between invocations.
257
+ #
258
+ def _shared_configuration #:nodoc:
259
+ super.merge!(:destination_root => self.destination_root)
260
+ end
261
+
262
+ def _cleanup_options_and_set(options, key) #:nodoc:
263
+ case options
264
+ when Array
265
+ %w(--force -f --skip -s).each { |i| options.delete(i) }
266
+ options << "--#{key}"
267
+ when Hash
268
+ [:force, :skip, "force", "skip"].each { |i| options.delete(i) }
269
+ options.merge!(key => true)
270
+ end
271
+ end
272
+
273
+ end
274
+ end
@@ -0,0 +1,103 @@
1
+ require 'thor/actions/empty_directory'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Create a new file relative to the destination root with the given data,
7
+ # which is the return value of a block or a data string.
8
+ #
9
+ # ==== Parameters
10
+ # destination<String>:: the relative path to the destination root.
11
+ # data<String|NilClass>:: the data to append to the file.
12
+ # config<Hash>:: give :verbose => false to not log the status.
13
+ #
14
+ # ==== Examples
15
+ #
16
+ # create_file "lib/fun_party.rb" do
17
+ # hostname = ask("What is the virtual hostname I should use?")
18
+ # "vhost.name = #{hostname}"
19
+ # end
20
+ #
21
+ # create_file "config/apach.conf", "your apache config"
22
+ #
23
+ def create_file(destination, data=nil, config={}, &block)
24
+ action CreateFile.new(self, destination, block || data.to_s, config)
25
+ end
26
+ alias :add_file :create_file
27
+
28
+ # AddFile is a subset of Template, which instead of rendering a file with
29
+ # ERB, it gets the content from the user.
30
+ #
31
+ class CreateFile < EmptyDirectory #:nodoc:
32
+ attr_reader :data
33
+
34
+ def initialize(base, destination, data, config={})
35
+ @data = data
36
+ super(base, destination, config)
37
+ end
38
+
39
+ # Checks if the content of the file at the destination is identical to the rendered result.
40
+ #
41
+ # ==== Returns
42
+ # Boolean:: true if it is identical, false otherwise.
43
+ #
44
+ def identical?
45
+ exists? && File.binread(destination) == render
46
+ end
47
+
48
+ # Holds the content to be added to the file.
49
+ #
50
+ def render
51
+ @render ||= if data.is_a?(Proc)
52
+ data.call
53
+ else
54
+ data
55
+ end
56
+ end
57
+
58
+ def invoke!
59
+ invoke_with_conflict_check do
60
+ FileUtils.mkdir_p(File.dirname(destination))
61
+ File.open(destination, 'wb') { |f| f.write render }
62
+ end
63
+ given_destination
64
+ end
65
+
66
+ protected
67
+
68
+ # Now on conflict we check if the file is identical or not.
69
+ #
70
+ def on_conflict_behavior(&block)
71
+ if identical?
72
+ say_status :identical, :blue
73
+ else
74
+ options = base.options.merge(config)
75
+ force_or_skip_or_conflict(options[:force], options[:skip], &block)
76
+ end
77
+ end
78
+
79
+ # If force is true, run the action, otherwise check if it's not being
80
+ # skipped. If both are false, show the file_collision menu, if the menu
81
+ # returns true, force it, otherwise skip.
82
+ #
83
+ def force_or_skip_or_conflict(force, skip, &block)
84
+ if force
85
+ say_status :force, :yellow
86
+ block.call unless pretend?
87
+ elsif skip
88
+ say_status :skip, :yellow
89
+ else
90
+ say_status :conflict, :red
91
+ force_or_skip_or_conflict(force_on_collision?, true, &block)
92
+ end
93
+ end
94
+
95
+ # Shows the file collision menu to the user and gets the result.
96
+ #
97
+ def force_on_collision?
98
+ base.shell.file_collision(destination){ render }
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,91 @@
1
+ require 'thor/actions/empty_directory'
2
+
3
+ class Thor
4
+ module Actions
5
+
6
+ # Copies recursively the files from source directory to root directory.
7
+ # If any of the files finishes with .tt, it's considered to be a template
8
+ # and is placed in the destination without the extension .tt. If any
9
+ # empty directory is found, it's copied and all .empty_directory files are
10
+ # ignored. Remember that file paths can also be encoded, let's suppose a doc
11
+ # directory with the following files:
12
+ #
13
+ # doc/
14
+ # components/.empty_directory
15
+ # README
16
+ # rdoc.rb.tt
17
+ # %app_name%.rb
18
+ #
19
+ # When invoked as:
20
+ #
21
+ # directory "doc"
22
+ #
23
+ # It will create a doc directory in the destination with the following
24
+ # files (assuming that the app_name is "blog"):
25
+ #
26
+ # doc/
27
+ # components/
28
+ # README
29
+ # rdoc.rb
30
+ # blog.rb
31
+ #
32
+ # ==== Parameters
33
+ # source<String>:: the relative path to the source root.
34
+ # destination<String>:: the relative path to the destination root.
35
+ # config<Hash>:: give :verbose => false to not log the status.
36
+ # If :recursive => false, does not look for paths recursively.
37
+ #
38
+ # ==== Examples
39
+ #
40
+ # directory "doc"
41
+ # directory "doc", "docs", :recursive => false
42
+ #
43
+ def directory(source, destination=nil, config={}, &block)
44
+ action Directory.new(self, source, destination || source, config, &block)
45
+ end
46
+
47
+ class Directory < EmptyDirectory #:nodoc:
48
+ attr_reader :source
49
+
50
+ def initialize(base, source, destination=nil, config={}, &block)
51
+ @source = File.expand_path(base.find_in_source_paths(source.to_s))
52
+ @block = block
53
+ super(base, destination, { :recursive => true }.merge(config))
54
+ end
55
+
56
+ def invoke!
57
+ base.empty_directory given_destination, config
58
+ execute!
59
+ end
60
+
61
+ def revoke!
62
+ execute!
63
+ end
64
+
65
+ protected
66
+
67
+ def execute!
68
+ lookup = config[:recursive] ? File.join(source, '**') : source
69
+ lookup = File.join(lookup, '{*,.[a-z]*}')
70
+
71
+ Dir[lookup].each do |file_source|
72
+ next if File.directory?(file_source)
73
+ file_destination = File.join(given_destination, file_source.gsub(source, '.'))
74
+ file_destination.gsub!('/./', '/')
75
+
76
+ case file_source
77
+ when /\.empty_directory$/
78
+ dirname = File.dirname(file_destination).gsub(/\/\.$/, '')
79
+ next if dirname == given_destination
80
+ base.empty_directory(dirname, config)
81
+ when /\.tt$/
82
+ destination = base.template(file_source, file_destination[0..-4], config, &@block)
83
+ else
84
+ destination = base.copy_file(file_source, file_destination, config, &@block)
85
+ end
86
+ end
87
+ end
88
+
89
+ end
90
+ end
91
+ end