bundler 1.0.0.beta.5 → 1.0.0.beta.8

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.

data/TODO.md CHANGED
@@ -1,16 +1,8 @@
1
1
  ## Bundler TODO list
2
2
 
3
- - Check to make sure ~/.bundler/bin is in $PATH
4
3
  - Cache Git repositories
4
+ - Build options
5
+ - A gem shit list
5
6
  - Interactive mode for bundle (install) to work out conflicts
6
7
  - bundle irb / bundle ruby / bundle [whatever] -> bundle exec
7
- - Make bundle (install) work when sudo might be needed
8
8
  - Generate a bundle stub into the application
9
- - Handle the following case (no remote fetching):
10
- 1) Depend on nokogiri, nokogiri is installed locally (ruby platform)
11
- 2) Run bundle package. nokogiri-1.4.2.gem is cached
12
- 3) Clone on jruby
13
- 4) Run `bundle install`
14
- Bundler will happily install the RUBY platform nokogiri because it
15
- is cached and bundler has not hit the remote source once so it does
16
- not know that there is a nokogiri-1.4.2-java.gem available
data/bin/bundle CHANGED
@@ -13,8 +13,9 @@ begin
13
13
  Bundler::CLI.start
14
14
  rescue Bundler::BundlerError => e
15
15
  Bundler.ui.error e.message
16
+ Bundler.ui.error e.backtrace.join("\n") if ENV["BUNDLE_DEBUG"]
16
17
  exit e.status_code
17
18
  rescue Interrupt
18
19
  Bundler.ui.error "\nQuitting..."
19
20
  exit 1
20
- end
21
+ end
@@ -15,7 +15,7 @@ module Bundler
15
15
  Gem::DefaultUserInteraction.ui = UI::RGProxy.new(Bundler.ui)
16
16
  end
17
17
 
18
- check_unknown_options! unless ARGV.include?("exec")
18
+ check_unknown_options! unless ARGV.include?("exec") || ARGV.include?("config")
19
19
 
20
20
  default_task :install
21
21
  class_option "no-color", :type => :boolean, :banner => "Disable colorization in output"
@@ -67,6 +67,7 @@ module Bundler
67
67
  Bundler.ui.warn "Install missing gems with `bundle install`"
68
68
  exit 1
69
69
  else
70
+ Bundler.load.lock
70
71
  Bundler.ui.info "The Gemfile's dependencies are satisfied"
71
72
  end
72
73
  end
@@ -96,7 +97,7 @@ module Bundler
96
97
  "Only output warnings and errors."
97
98
  method_option "local", :type => :boolean, :banner =>
98
99
  "Do not attempt to fetch gems remotely and use the gem cache instead"
99
- method_option "binstubs", :type => :boolean, :banner =>
100
+ method_option "binstubs", :type => :string, :lazy_default => "bin", :banner =>
100
101
  "Generate bin stubs for bundled gems to ./bin"
101
102
  def install(path = nil)
102
103
  opts = options.dup
@@ -106,13 +107,13 @@ module Bundler
106
107
  # Can't use Bundler.settings for this because settings needs gemfile.dirname
107
108
  ENV['BUNDLE_GEMFILE'] = opts[:gemfile] if opts[:gemfile]
108
109
  Bundler.settings[:path] = path if path
109
- Bundler.settings[:bin] = 'bin' if opts[:binstubs]
110
+ Bundler.settings[:bin] = opts["binstubs"] if opts[:binstubs]
110
111
  Bundler.settings[:disable_shared_gems] = '1' if options["disable-shared-gems"] || path
111
112
  Bundler.settings.without = opts[:without]
112
113
  Bundler.ui.be_quiet! if opts[:quiet]
113
114
 
114
115
  Installer.install(Bundler.root, Bundler.definition, opts)
115
- cache if Bundler.root.join("vendor/cache").exist?
116
+ Bundler.load.cache if Bundler.root.join("vendor/cache").exist?
116
117
  Bundler.ui.confirm "Your bundle is complete! " +
117
118
  "Use `bundle show [gemname]` to see where a bundled gem is installed."
118
119
  rescue GemNotFound => e
@@ -134,13 +135,13 @@ module Bundler
134
135
 
135
136
  if gems.empty? && sources.empty?
136
137
  # We're doing a full update
137
- FileUtils.rm_f Bundler.root.join("Gemfile.lock")
138
+ Bundler.definition(true)
138
139
  else
139
140
  Bundler.definition(:gems => gems, :sources => sources)
140
141
  end
141
142
 
142
143
  Installer.install Bundler.root, Bundler.definition, "update" => true
143
- cache if Bundler.root.join("vendor/cache").exist?
144
+ Bundler.load.cache if Bundler.root.join("vendor/cache").exist?
144
145
  Bundler.ui.confirm "Your bundle is updated! " +
145
146
  "Use `bundle show [gemname]` to see where a bundled gem is installed."
146
147
  end
@@ -161,6 +162,8 @@ module Bundler
161
162
  Calling show with [GEM] will list the exact location of that gem on your machine.
162
163
  D
163
164
  def show(gem_name = nil)
165
+ Bundler.load.lock
166
+
164
167
  if gem_name
165
168
  Bundler.ui.info locate_gem(gem_name)
166
169
  else
@@ -172,11 +175,13 @@ module Bundler
172
175
  end
173
176
  map %w(list) => "show"
174
177
 
175
- desc "cache", "Cache all the gems to vendor/cache"
178
+ desc "cache", "Cache all the gems to vendor/cache", :hide => true
176
179
  method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache."
177
180
  def cache
181
+ Bundler.definition.resolve_with_cache!
178
182
  Bundler.load.cache
179
- Bundler.load.prune_cache unless options[:no_prune]
183
+ Bundler.settings[:no_prune] = true if options[:no_prune]
184
+ Bundler.load.lock
180
185
  rescue GemNotFound => e
181
186
  Bundler.ui.error(e.message)
182
187
  Bundler.ui.warn "Run `bundle install` to install missing gems."
@@ -194,7 +199,7 @@ module Bundler
194
199
  def package
195
200
  install
196
201
  # TODO: move cache contents here now that all bundles are locked
197
- cache
202
+ Bundler.load.cache
198
203
  end
199
204
  map %w(pack) => :package
200
205
 
@@ -234,6 +239,48 @@ module Bundler
234
239
  end
235
240
  end
236
241
 
242
+ desc "config NAME [VALUE]", "retrieve or set a configuration value"
243
+ long_desc <<-D
244
+ Retrieves or sets a configuration value. If only parameter is provided, retrieve the value. If two parameters are provided, replace the
245
+ existing value with the newly provided one.
246
+
247
+ By default, setting a configuration value sets it for all projects
248
+ on the machine. If you want to set the configuration for a specific
249
+ project, use the --local flag.
250
+
251
+ If a global setting is superceded by local configuration, this command
252
+ will show the current value, as well as any superceded values and
253
+ where they were specified.
254
+ D
255
+ def config(name, *values)
256
+ locations = Bundler.settings.locations(name)
257
+
258
+ if values.empty?
259
+ # TODO: Say something more useful here
260
+ locations.each do |location, value|
261
+ if value
262
+ Bundler.ui.info "#{location}: #{value}"
263
+ end
264
+ end
265
+ else
266
+ if local = locations[:local]
267
+ Bundler.ui.info "Your application has set #{name} to #{local.inspect}. This will override the " \
268
+ "system value you are currently setting"
269
+ end
270
+
271
+ if global = locations[:global]
272
+ Bundler.ui.info "You are replacing the current system value of #{name}, which is currently #{global}"
273
+ end
274
+
275
+ if env = locations[:env]
276
+ Bundler.ui.info "You have set a bundler environment variable for #{env}. This will take precedence " \
277
+ "over the system value you are setting"
278
+ end
279
+
280
+ Bundler.settings.set_global(name, values.join(" "))
281
+ end
282
+ end
283
+
237
284
  desc "open GEM", "Opens the source directory of the given bundled gem"
238
285
  def open(name)
239
286
  editor = [ENV['BUNDLER_EDITOR'], ENV['VISUAL'], ENV['EDITOR']].find{|e| !e.nil? && !e.empty? }
@@ -297,14 +344,10 @@ module Bundler
297
344
  def locate_gem(name)
298
345
  spec = Bundler.load.specs.find{|s| s.name == name }
299
346
  raise GemNotFound, "Could not find gem '#{name}' in the current bundle." unless spec
347
+ if spec.name == 'bundler'
348
+ return File.expand_path('../../../', __FILE__)
349
+ end
300
350
  spec.full_gem_path
301
351
  end
302
-
303
- def self.printable_tasks
304
- tasks = super.dup
305
- nodoc = /^bundle (cache)/
306
- tasks.reject!{|t| t.first =~ nodoc }
307
- tasks
308
- end
309
352
  end
310
353
  end
@@ -34,22 +34,24 @@ module Bundler
34
34
  @dependencies, @sources, @unlock = dependencies, sources, unlock
35
35
  @remote = false
36
36
  @specs = nil
37
- @unlock[:gems] ||= []
38
- @unlock[:sources] ||= []
39
37
 
40
- if lockfile && File.exists?(lockfile)
38
+ if lockfile && File.exists?(lockfile) && unlock != true
41
39
  locked = LockfileParser.new(File.read(lockfile))
42
40
  @platforms = locked.platforms
43
41
  @locked_deps = locked.dependencies
44
42
  @last_resolve = SpecSet.new(locked.specs)
45
43
  @locked_sources = locked.sources
46
44
  else
45
+ @unlock = {}
47
46
  @platforms = []
48
47
  @locked_deps = []
49
48
  @last_resolve = SpecSet.new([])
50
49
  @locked_sources = []
51
50
  end
52
51
 
52
+ @unlock[:gems] ||= []
53
+ @unlock[:sources] ||= []
54
+
53
55
  current_platform = Gem.platforms.map { |p| p.to_generic }.compact.last
54
56
  @platforms |= [current_platform]
55
57
 
@@ -165,10 +167,13 @@ module Bundler
165
167
  out << "\n"
166
168
  out << "DEPENDENCIES\n"
167
169
 
170
+ handled = []
168
171
  dependencies.
169
172
  sort_by { |d| d.name }.
170
173
  each do |dep|
174
+ next if handled.include?(dep.name)
171
175
  out << dep.to_lock
176
+ handled << dep.name
172
177
  end
173
178
 
174
179
  out
@@ -183,7 +188,9 @@ module Bundler
183
188
  end
184
189
 
185
190
  def converge_sources
186
- @sources = (@locked_sources & @sources) | @sources
191
+ @sources.map! do |source|
192
+ @locked_sources.find { |s| s == source } || source
193
+ end
187
194
  @sources.each do |source|
188
195
  source.unlock! if source.respond_to?(:unlock!) && @unlock[:sources].include?(source.name)
189
196
  end
@@ -192,9 +199,7 @@ module Bundler
192
199
  def converge_dependencies
193
200
  (@dependencies + @locked_deps).each do |dep|
194
201
  if dep.source
195
- source = @sources.find { |s| dep.source == s }
196
- raise "Something went wrong, there is no matching source" unless source
197
- dep.source = source
202
+ dep.source = @sources.find { |s| dep.source == s }
198
203
  end
199
204
  end
200
205
  end
@@ -20,14 +20,16 @@ module Bundler
20
20
  @env = nil
21
21
  end
22
22
 
23
- def gemspec(opts)
23
+ def gemspec(opts = nil)
24
24
  path = opts && opts[:path] || '.'
25
25
  name = opts && opts[:name] || '*'
26
26
  development_group = opts && opts[:development_group] || :development
27
27
  gemspecs = Dir[File.join(path, "#{name}.gemspec")]
28
+
28
29
  case gemspecs.size
29
30
  when 1
30
31
  spec = Gem::Specification.load(gemspecs.first)
32
+ gem spec.name, :path => path
31
33
  spec.runtime_dependencies.each do |dep|
32
34
  gem dep.name, dep.requirement.to_s
33
35
  end
@@ -49,7 +51,7 @@ module Bundler
49
51
  end
50
52
 
51
53
  options = Hash === args.last ? args.pop : {}
52
- version = args.last || ">= 0"
54
+ version = args || [">= 0"]
53
55
  if group = options[:groups] || options[:group]
54
56
  options[:group] = group
55
57
  end
@@ -57,6 +59,21 @@ module Bundler
57
59
  _deprecated_options(options)
58
60
  _normalize_options(name, version, options)
59
61
 
62
+ dep = Dependency.new(name, version, options)
63
+
64
+ if current = @dependencies.find { |d| d.name == dep.name }
65
+ if current.requirement != dep.requirement
66
+ raise DslError, "You cannot specify the same gem twice with different version requirements. " \
67
+ "You specified: #{current.name} (#{current.requirement}) and " \
68
+ "#{dep.name} (#{dep.requirement})"
69
+ end
70
+
71
+ if current.source != dep.source
72
+ raise DslError, "You cannot specify the same gem twice coming from different sources. You " \
73
+ "specified that #{dep.name} (#{dep.requirement}) should come from " \
74
+ "#{current.source || 'an unspecfied source'} and #{dep.source}"
75
+ end
76
+ end
60
77
  @dependencies << Dependency.new(name, version, options)
61
78
  end
62
79
 
@@ -200,7 +217,7 @@ module Bundler
200
217
  # Normalize git and path options
201
218
  ["git", "path"].each do |type|
202
219
  if param = opts[type]
203
- options = _version?(version) ? opts.merge("name" => name, "version" => version) : opts.dup
220
+ options = _version?(version.first) ? opts.merge("name" => name, "version" => version.first) : opts.dup
204
221
  source = send(type, param, options, :prepend => true) {}
205
222
  opts["source"] = source
206
223
  end
@@ -5,6 +5,9 @@ module Bundler
5
5
  def initialize(root, definition)
6
6
  @root = root
7
7
  @definition = definition
8
+
9
+ env_file = root.join('.bundle/environment.rb')
10
+ env_file.rmtree if env_file.exist?
8
11
  end
9
12
 
10
13
  def inspect
@@ -33,9 +36,6 @@ module Bundler
33
36
  end
34
37
 
35
38
  def lock
36
- env_file = root.join('.bundle/environment.rb')
37
- env_file.rmtree if env_file.exist?
38
-
39
39
  contents = @definition.to_lock
40
40
 
41
41
  File.open(root.join('Gemfile.lock'), 'w') do |f|
@@ -60,18 +60,19 @@ module Bundler
60
60
 
61
61
  def parse_dependency(line)
62
62
  if line =~ %r{^ {2}#{NAME_VERSION}(!)?$}
63
- name, version, pinned = $1, $2, $3
63
+ name, version, pinned = $1, $2, $4
64
+ version = version.split(",").map { |d| d.strip } if version
64
65
 
65
66
  dep = Bundler::Dependency.new(name, version)
66
67
 
67
- if pinned
68
+ if pinned && dep.name != 'bundler'
68
69
  dep.source = @specs.find { |s| s.name == dep.name }.source
69
70
 
70
71
  # Path sources need to know what the default name / version
71
72
  # to use in the case that there are no gemspecs present. A fake
72
73
  # gemspec is created based on the version set on the dependency
73
74
  # TODO: Use the version from the spec instead of from the dependency
74
- if version =~ /^= (.+)$/ && dep.source.is_a?(Bundler::Source::Path)
75
+ if version && version.size == 1 && version.first =~ /^= (.+)$/ && dep.source.is_a?(Bundler::Source::Path)
75
76
  dep.source.name = name
76
77
  dep.source.version = $1
77
78
  end
@@ -103,4 +104,4 @@ module Bundler
103
104
  end
104
105
 
105
106
  end
106
- end
107
+ end
@@ -111,6 +111,11 @@ module Gem
111
111
  end
112
112
 
113
113
  def add_bundler_dependencies(*groups)
114
+ Bundler.ui.warn "#add_bundler_dependencies is deprecated and will " \
115
+ "be removed in Bundler 1.0. Instead, please use the #gemspec method " \
116
+ "in your Gemfile, which will pull in any dependencies specified in " \
117
+ "your gemspec"
118
+
114
119
  groups = [:default] if groups.empty?
115
120
  Bundler.definition.dependencies.each do |dep|
116
121
  if dep.groups.include?(:development)
@@ -4,11 +4,6 @@ module Bundler
4
4
  class Runtime < Environment
5
5
  include SharedHelpers
6
6
 
7
- def initialize(*)
8
- super
9
- lock
10
- end
11
-
12
7
  def setup(*groups)
13
8
  # Has to happen first
14
9
  clean_load_path
@@ -35,9 +30,19 @@ module Bundler
35
30
  load_paths = spec.load_paths.reject {|path| $LOAD_PATH.include?(path)}
36
31
  $LOAD_PATH.unshift(*load_paths)
37
32
  end
33
+
34
+ lock
35
+
38
36
  self
39
37
  end
40
38
 
39
+ REGEXPS = [
40
+ /^no such file to load -- (.+)$/i,
41
+ /^Missing \w+ (?:file\s*)?([^\s]+.rb)$/i,
42
+ /^Missing API definition file in (.+)$/i,
43
+ /^cannot load such file -- (.+)$/i,
44
+ ]
45
+
41
46
  def require(*groups)
42
47
  groups.map! { |g| g.to_sym }
43
48
  groups = [:default] if groups.empty?
@@ -47,17 +52,19 @@ module Bundler
47
52
  # groups
48
53
  next unless (dep.groups & groups).any?
49
54
 
55
+ required_file = nil
56
+
50
57
  begin
51
58
  # Loop through all the specified autorequires for the
52
59
  # dependency. If there are none, use the dependency's name
53
60
  # as the autorequire.
54
61
  Array(dep.autorequire || dep.name).each do |file|
62
+ required_file = file
55
63
  Kernel.require file
56
64
  end
57
- rescue LoadError
58
- # Only let a LoadError through if the autorequire was explicitly
59
- # specified by the user.
60
- raise if dep.autorequire
65
+ rescue LoadError => e
66
+ REGEXPS.find { |r| r =~ e.message }
67
+ raise if dep.autorequire || $1 != required_file
61
68
  end
62
69
  end
63
70
  end
@@ -80,18 +87,29 @@ module Bundler
80
87
  next if spec.name == 'bundler'
81
88
  spec.source.cache(spec) if spec.source.respond_to?(:cache)
82
89
  end
90
+ prune_cache unless Bundler.settings[:no_prune]
83
91
  end
84
92
 
85
93
  def prune_cache
86
94
  FileUtils.mkdir_p(cache_path)
87
95
 
88
- Bundler.ui.info "Removing outdated .gem files from vendor/cache"
89
- Pathname.glob(cache_path.join("*.gem").to_s).each do |gem_path|
90
- cached_spec = Gem::Format.from_file_by_path(gem_path).spec
91
- next unless Gem::Platform.match(cached_spec.platform)
92
- unless specs.any?{|s| s.full_name == cached_spec.full_name }
93
- Bundler.ui.info " * #{File.basename(gem_path)}"
94
- gem_path.rmtree
96
+ resolve = @definition.resolve
97
+ cached = Dir["#{cache_path}/*.gem"]
98
+
99
+ cached = cached.delete_if do |path|
100
+ spec = Gem::Format.from_file_by_path(path).spec
101
+
102
+ resolve.any? do |s|
103
+ s.name == spec.name && s.version == spec.version
104
+ end
105
+ end
106
+
107
+ if cached.any?
108
+ Bundler.ui.info "Removing outdated .gem files from vendor/cache"
109
+
110
+ cached.each do |path|
111
+ Bundler.ui.info " * #{File.basename(path)}"
112
+ File.delete(path)
95
113
  end
96
114
  end
97
115
  end