bundler 1.0.0.beta.1 → 1.0.0.beta.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.

data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ### Note: the master branch is currently unstable while 0.10 is being worked on.<br>The current stable version of bundler is in the branch named `v0.9`.
1
+ ### Note: the master branch is currently unstable while 1.0 is in beta.<br>The current stable version of bundler is in the branch named `v0.9`.
2
2
 
3
3
  ## Bundler : A gem to bundle gems
4
4
 
data/lib/bundler.rb CHANGED
@@ -40,7 +40,6 @@ module Bundler
40
40
  class GemfileNotFound < BundlerError; status_code(10) ; end
41
41
  class GemNotFound < BundlerError; status_code(7) ; end
42
42
  class GemfileError < BundlerError; status_code(4) ; end
43
- class GemfileChanged < GemfileError; status_code(4) ; end
44
43
  class PathError < BundlerError; status_code(13) ; end
45
44
  class GitError < BundlerError; status_code(11) ; end
46
45
  class GemspecError < BundlerError; status_code(14) ; end
@@ -93,7 +92,7 @@ module Bundler
93
92
  end
94
93
 
95
94
  def setup(*groups)
96
- return @setup if @setup
95
+ return @setup if defined?(@setup) && @setup
97
96
 
98
97
  if groups.empty?
99
98
  # Load all groups, but only once
data/lib/bundler/cli.rb CHANGED
@@ -89,6 +89,10 @@ module Bundler
89
89
  "Don't remove stale gems from the cache."
90
90
  method_option "no-cache", :type => :boolean, :banner =>
91
91
  "Don't update the existing gem cache."
92
+ method_option "quiet", :type => :boolean, :banner =>
93
+ "Only output warnings and errors."
94
+ method_option "local", :type => :boolean, :banner =>
95
+ "Do not attempt to fetch gems remotely and use the gem cache instead"
92
96
  def install(path = nil)
93
97
  opts = options.dup
94
98
  opts[:without] ||= []
@@ -99,6 +103,7 @@ module Bundler
99
103
  Bundler.settings[:path] = path if path
100
104
  Bundler.settings[:disable_shared_gems] = '1' if options["disable-shared-gems"] || path
101
105
  Bundler.settings.without = opts[:without]
106
+ Bundler.ui.be_quiet! if opts[:quiet]
102
107
 
103
108
  Installer.install(Bundler.root, Bundler.definition, opts)
104
109
  cache if Bundler.root.join("vendor/cache").exist?
@@ -129,6 +134,9 @@ module Bundler
129
134
  end
130
135
 
131
136
  Installer.install Bundler.root, Bundler.definition
137
+ cache if Bundler.root.join("vendor/cache").exist?
138
+ Bundler.ui.confirm "Your bundle is updated! " +
139
+ "Use `bundle show [gemname]` to see where a bundled gem is installed."
132
140
  end
133
141
 
134
142
  desc "lock", "Locks the bundle to the current set of dependencies, including all child dependencies."
@@ -249,9 +257,14 @@ module Bundler
249
257
  map %w(-v --version) => :version
250
258
 
251
259
  desc 'viz', "Generates a visual dependency graph"
252
- method_option :file, :type => :string, :default => 'gem_graph.png', :aliases => '-f', :banner => "Show the version with each gem name."
253
- method_option :version, :type => :boolean, :default => false, :aliases => '-v', :banner => "Show the version with each gem name."
254
- method_option :requirements, :type => :boolean, :default => false, :aliases => '-r', :banner => "Show the requirement for each dependency."
260
+ long_desc <<-D
261
+ Viz generates a PNG file of the current Gemfile as a dependency graph.
262
+ Viz requires the ruby-graphviz gem (and its dependencies).
263
+ The associated gems must also be installed via 'bundle install'.
264
+ D
265
+ method_option :file, :type => :string, :default => 'gem_graph.png', :aliases => '-f', :banner => "The name to use for the generated png file."
266
+ method_option :version, :type => :boolean, :default => false, :aliases => '-v', :banner => "Set to show each gem version."
267
+ method_option :requirements, :type => :boolean, :default => false, :aliases => '-r', :banner => "Set to show the version of each required dependency."
255
268
  def viz
256
269
  output_file = File.expand_path(options[:file])
257
270
  graph = Graph.new( Bundler.load )
@@ -32,6 +32,7 @@ module Bundler
32
32
 
33
33
  def initialize(lockfile, dependencies, sources, unlock)
34
34
  @dependencies, @sources, @unlock = dependencies, sources, unlock
35
+ @remote = false
35
36
  @specs = nil
36
37
  @unlock[:gems] ||= []
37
38
  @unlock[:sources] ||= []
@@ -55,8 +56,15 @@ module Bundler
55
56
  converge
56
57
  end
57
58
 
59
+ def resolve_with_cache!
60
+ raise "Specs already loaded" if @specs
61
+ @sources.each { |s| s.cached! }
62
+ specs
63
+ end
64
+
58
65
  def resolve_remotely!
59
66
  raise "Specs already loaded" if @specs
67
+ @remote = true
60
68
  @sources.each { |s| s.remote! }
61
69
  specs
62
70
  end
@@ -101,7 +109,7 @@ module Bundler
101
109
  end
102
110
 
103
111
  # Run a resolve against the locally available gems
104
- Resolver.resolve(expanded_dependencies, index, source_requirements, @last_resolve)
112
+ @last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, @last_resolve)
105
113
  end
106
114
  end
107
115
  end
@@ -131,8 +139,9 @@ module Bundler
131
139
  # Find all specs for this source
132
140
  resolve.
133
141
  select { |s| s.source == source }.
134
- sort_by { |s| [s.name, s.platform.to_s == 'ruby' ? "\0" : s.platform.to_s] }.
142
+ sort_by { |s| s.name }.
135
143
  each do |spec|
144
+ next if spec.name == 'bundler'
136
145
  out << spec.to_lock
137
146
  end
138
147
  out << "\n"
@@ -195,13 +204,16 @@ module Bundler
195
204
  s.source = @sources.find { |src| s.source == src }
196
205
 
197
206
  next if s.source.nil? || @unlock[:sources].include?(s.name)
207
+ # If the spec is from a path source and it doesn't exist anymore
208
+ # then we just unlock it.
209
+ next if s.source.instance_of?(Source::Path) && s.source.specs[s].empty?
198
210
 
199
211
  converged << s
200
212
  end
201
213
 
202
214
  resolve = SpecSet.new(converged)
203
- resolve = resolve.for(expand_dependencies(deps), @unlock[:gems])
204
- @last_resolve.select!(resolve.names)
215
+ resolve = resolve.for(expand_dependencies(deps, true), @unlock[:gems])
216
+ @last_resolve = resolve
205
217
  end
206
218
 
207
219
  def in_locked_deps?(dep)
@@ -215,14 +227,14 @@ module Bundler
215
227
  end
216
228
 
217
229
  def expanded_dependencies
218
- @expanded_dependencies ||= expand_dependencies(dependencies)
230
+ @expanded_dependencies ||= expand_dependencies(dependencies, @remote)
219
231
  end
220
232
 
221
- def expand_dependencies(dependencies)
233
+ def expand_dependencies(dependencies, remote = false)
222
234
  deps = []
223
235
  dependencies.each do |dep|
224
236
  dep.gem_platforms(@platforms).each do |p|
225
- deps << DepProxy.new(dep, p)
237
+ deps << DepProxy.new(dep, p) if remote || p == Gem::Platform.local.to_generic
226
238
  end
227
239
  end
228
240
  deps
data/lib/bundler/dsl.rb CHANGED
@@ -20,6 +20,29 @@ module Bundler
20
20
  @env = nil
21
21
  end
22
22
 
23
+ def gemspec(opts)
24
+ path = opts && opts[:path] || '.'
25
+ name = opts && opts[:name] || '*'
26
+ development_group = opts && opts[:development_group] || :development
27
+ gemspecs = Dir[File.join(path, "#{name}.gemspec")]
28
+ case gemspecs.size
29
+ when 1
30
+ spec = Gem::Specification.load(gemspecs.first)
31
+ spec.runtime_dependencies.each do |dep|
32
+ gem dep.name, dep.requirement.to_s
33
+ end
34
+ group(development_group) do
35
+ spec.development_dependencies.each do |dep|
36
+ gem dep.name, dep.requirement.to_s
37
+ end
38
+ end
39
+ when 0
40
+ raise InvalidOption, "There are no gemspecs at #{path}."
41
+ else
42
+ raise InvalidOption, "There are multiple gemspecs at #{path}. Please use the :name option to specify which one."
43
+ end
44
+ end
45
+
23
46
  def gem(name, *args)
24
47
  options = Hash === args.last ? args.pop : {}
25
48
  version = args.last || ">= 0"
data/lib/bundler/index.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  module Bundler
2
2
  class Index
3
+ include Enumerable
4
+
3
5
  def self.build
4
6
  i = new
5
7
  yield i
@@ -31,8 +33,8 @@ module Bundler
31
33
  end
32
34
  end
33
35
 
34
- def search_for_all_platforms(dependency)
35
- specs = @specs[dependency.name]
36
+ def search_for_all_platforms(dependency, base = [])
37
+ specs = @specs[dependency.name] + base
36
38
 
37
39
  wants_prerelease = dependency.requirement.prerelease?
38
40
  only_prerelease = specs.all? {|spec| spec.version.prerelease? }
@@ -79,6 +81,12 @@ module Bundler
79
81
  self
80
82
  end
81
83
 
84
+ def ==(o)
85
+ all? do |s|
86
+ s2 = o[s].first and (s.dependencies & s2.dependencies).empty?
87
+ end
88
+ end
89
+
82
90
  private
83
91
 
84
92
  def search_by_spec(spec)
@@ -16,7 +16,9 @@ module Bundler
16
16
 
17
17
  # Since we are installing, we can resolve the definition
18
18
  # using remote specs
19
- @definition.resolve_remotely!
19
+ options["local"] ?
20
+ @definition.resolve_with_cache! :
21
+ @definition.resolve_remotely!
20
22
 
21
23
  # Ensure that BUNDLE_PATH exists
22
24
  FileUtils.mkdir_p(Bundler.bundle_path)
@@ -45,7 +45,7 @@ module Bundler
45
45
  end
46
46
 
47
47
  def __materialize__
48
- @specification = source[self]
48
+ @specification = source.specs.search(Gem::Dependency.new(name, version)).last
49
49
  end
50
50
 
51
51
  def respond_to?(*args)
@@ -49,11 +49,16 @@ module Bundler
49
49
 
50
50
  def to_specs
51
51
  specs = {}
52
- each do |s|
53
- next if specs[s.platform]
54
- lazy_spec = LazySpecification.new(s.name, s.version, s.platform, s.source)
55
- lazy_spec.dependencies.replace s.dependencies
56
- specs[s.platform] = lazy_spec
52
+
53
+ @activated.each do |p|
54
+ if s = @specs[p]
55
+ platform = Gem::Platform.new(s.platform).to_generic
56
+ next if specs[platform]
57
+
58
+ lazy_spec = LazySpecification.new(name, version, platform, source)
59
+ lazy_spec.dependencies.replace s.dependencies
60
+ specs[platform] = lazy_spec
61
+ end
57
62
  end
58
63
  specs.values
59
64
  end
@@ -125,11 +130,12 @@ module Bundler
125
130
  end
126
131
 
127
132
  def initialize(index, source_requirements, base)
128
- @errors = {}
129
- @stack = []
130
- @base = base
131
- @index = index
132
- @source_requirements = source_requirements
133
+ @errors = {}
134
+ @stack = []
135
+ @base = base
136
+ @index = index
137
+ @missing_gems = Hash.new(0)
138
+ @source_requirements = source_requirements
133
139
  end
134
140
 
135
141
  def debug
@@ -145,7 +151,7 @@ module Bundler
145
151
  end
146
152
 
147
153
  def start(reqs)
148
- activated = {}
154
+ activated = {}
149
155
 
150
156
  resolve(reqs, activated)
151
157
  end
@@ -184,6 +190,7 @@ module Bundler
184
190
  if existing = activated[current.name] or current.name == 'bundler'
185
191
  # Force the current
186
192
  if current.name == 'bundler' && !existing
193
+ # TODO: handle existing still == nil
187
194
  existing = search(DepProxy.new(Gem::Dependency.new('bundler', VERSION), Gem::Platform::RUBY)).first
188
195
  activated[current.name] = existing
189
196
  end
@@ -259,6 +266,17 @@ module Bundler
259
266
  end
260
267
  raise GemNotFound, message
261
268
  else
269
+ if @missing_gems[current] >= 5
270
+ msg = "When trying to resolve #{current.required_by.last}, \n" \
271
+ "Bundler could not find its dependency \n" \
272
+ "#{current} in any source\n"
273
+
274
+ raise Bundler::GemNotFound, msg
275
+ end
276
+
277
+ @missing_gems[current] += 1
278
+
279
+ debug { " Could not find #{current} by #{current.required_by.last}" }
262
280
  @errors[current.name] = [nil, current]
263
281
  end
264
282
  end
@@ -291,8 +309,8 @@ module Bundler
291
309
  spec_group.required_by << requirement
292
310
 
293
311
  activated[spec_group.name] = spec_group
294
- debug { " Activating: #{spec.name} (#{spec.version})" }
295
- debug { spec.required_by.map { |d| " * #{d.name} (#{d.requirement})" }.join("\n") }
312
+ debug { " Activating: #{spec_group.name} (#{spec_group.version})" }
313
+ debug { spec_group.required_by.map { |d| " * #{d.name} (#{d.requirement})" }.join("\n") }
296
314
 
297
315
  dependencies = spec_group.activate_platform(requirement.__platform)
298
316
 
@@ -323,12 +341,13 @@ module Bundler
323
341
  end
324
342
 
325
343
  def search(dep)
326
- results = @base[dep.name]
327
-
328
- if results.empty?
329
- index = @source_requirements[dep.name] || @index
330
- results = index.search_for_all_platforms(dep.dep)
344
+ if base = @base[dep.name] and base.any?
345
+ d = Gem::Dependency.new(base.first.name, base.first.version)
346
+ else
347
+ d = dep.dep
331
348
  end
349
+ index = @source_requirements[d.name] || @index
350
+ results = index.search_for_all_platforms(d, @base[d.name])
332
351
 
333
352
  if results.any?
334
353
  version = results.first.version
@@ -20,7 +20,15 @@ module Bundler
20
20
  # Activate the specs
21
21
  specs.each do |spec|
22
22
  unless spec.loaded_from
23
- raise GemNotFound, "#{spec.full_name} is cached, but not installed."
23
+ raise GemNotFound, "#{spec.full_name} is missing. Run `bundle` to get it."
24
+ end
25
+
26
+ if activated_spec = Gem.loaded_specs[spec.name] and activated_spec.version != spec.version
27
+ e = Gem::LoadError.new "You have already activated #{activated_spec.name} #{activated_spec.version}, " \
28
+ "but your Gemfile requires #{spec.name} #{spec.version}. Consider using bundle exec."
29
+ e.name = spec.name
30
+ e.version_requirement = Gem::Requirement.new(spec.version.to_s)
31
+ raise e
24
32
  end
25
33
 
26
34
  Gem.loaded_specs[spec.name] = spec
@@ -15,8 +15,8 @@ module Bundler
15
15
  @options = options
16
16
  @remotes = (options["remotes"] || []).map { |r| normalize_uri(r) }
17
17
  @allow_remote = false
18
+ @allow_cached = false
18
19
  # Hardcode the paths for now
19
- @installed = {}
20
20
  @caches = [ Bundler.app_cache ] + Gem.path.map { |p| File.expand_path("#{p}/cache") }
21
21
  @spec_fetch_map = {}
22
22
  end
@@ -25,11 +25,8 @@ module Bundler
25
25
  @allow_remote = true
26
26
  end
27
27
 
28
- def [](spec)
29
- installed_specs[spec].first ||
30
- @allow_remote && (
31
- cached_specs[spec].first ||
32
- remote_specs[spec].first)
28
+ def cached!
29
+ @allow_cached = true
33
30
  end
34
31
 
35
32
  def hash
@@ -70,7 +67,7 @@ module Bundler
70
67
  end
71
68
 
72
69
  def specs
73
- @specs ||= @allow_remote ? fetch_specs : installed_specs
70
+ @specs ||= fetch_specs
74
71
  end
75
72
 
76
73
  def fetch(spec)
@@ -81,13 +78,13 @@ module Bundler
81
78
  def install(spec)
82
79
  path = cached_gem(spec)
83
80
 
84
- if @installed[spec.full_name]
81
+ if installed_specs[spec].any?
85
82
  Bundler.ui.info "Using #{spec.name} (#{spec.version}) "
86
83
  return
87
- else
88
- Bundler.ui.info "Installing #{spec.name} (#{spec.version}) "
89
84
  end
90
85
 
86
+ Bundler.ui.info "Installing #{spec.name} (#{spec.version}) "
87
+
91
88
  install_path = Bundler.requires_sudo? ? Bundler.tmp : Gem.dir
92
89
  installer = Gem::Installer.new path,
93
90
  :install_dir => install_path,
@@ -141,8 +138,8 @@ module Bundler
141
138
  def fetch_specs
142
139
  Index.build do |idx|
143
140
  idx.use installed_specs
144
- idx.use cached_specs
145
- idx.use remote_specs
141
+ idx.use cached_specs if @allow_cached
142
+ idx.use remote_specs if @allow_remote
146
143
  end
147
144
  end
148
145
 
@@ -150,10 +147,20 @@ module Bundler
150
147
  @installed_specs ||= begin
151
148
  idx = Index.new
152
149
  Gem::SourceIndex.from_installed_gems.to_a.reverse.each do |name, spec|
153
- @installed[spec.full_name] = true
150
+ next if name == 'bundler'
154
151
  spec.source = self
155
152
  idx << spec
156
153
  end
154
+ # Always have bundler locally
155
+ bundler = Gem::Specification.new do |s|
156
+ s.name = 'bundler'
157
+ s.version = VERSION
158
+ s.platform = Gem::Platform::RUBY
159
+ s.source = self
160
+ # TODO: Remove this
161
+ s.loaded_from = 'w0t'
162
+ end
163
+ idx << bundler
157
164
  idx
158
165
  end
159
166
  end
@@ -163,6 +170,7 @@ module Bundler
163
170
  idx = Index.new
164
171
  @caches.each do |path|
165
172
  Dir["#{path}/*.gem"].each do |gemfile|
173
+ next if name == 'bundler'
166
174
  s = Gem::Format.from_file_by_path(gemfile).spec
167
175
  s.source = self
168
176
  idx << s
@@ -183,6 +191,7 @@ module Bundler
183
191
  Gem.sources = ["#{uri}"]
184
192
  fetch_all_remote_specs do |n,v|
185
193
  v.each do |name, version, platform|
194
+ next if name == 'bundler'
186
195
  spec = RemoteSpecification.new(name, version, platform, uri)
187
196
  spec.source = self
188
197
  # Temporary hack until this can be figured out better
@@ -237,7 +246,7 @@ module Bundler
237
246
  class Path
238
247
  attr_reader :path, :options
239
248
  # Kind of a hack, but needed for the lock file parser
240
- attr_accessor :name, :version
249
+ attr_accessor :version
241
250
 
242
251
  DEFAULT_GLOB = "{,*/}*.gemspec"
243
252
 
@@ -245,6 +254,7 @@ module Bundler
245
254
  @options = options
246
255
  @glob = options["glob"] || DEFAULT_GLOB
247
256
 
257
+ @allow_cached = false
248
258
  @allow_remote = false
249
259
 
250
260
  if options["path"]
@@ -259,6 +269,10 @@ module Bundler
259
269
  @allow_remote = true
260
270
  end
261
271
 
272
+ def cached!
273
+ @allow_cached = true
274
+ end
275
+
262
276
  def self.from_lock(options)
263
277
  new(options.merge("path" => options.delete("remote")))
264
278
  end
@@ -340,10 +354,6 @@ module Bundler
340
354
  index
341
355
  end
342
356
 
343
- def [](spec)
344
- specs[spec].first
345
- end
346
-
347
357
  def local_specs
348
358
  @local_specs ||= load_spec_files
349
359
  end
@@ -484,8 +494,9 @@ module Bundler
484
494
  @revision = nil
485
495
  end
486
496
 
497
+ # TODO: actually cache git specs
487
498
  def specs
488
- if @allow_remote && !@update
499
+ if (@allow_remote || @allow_cached) && !@update
489
500
  # Start by making sure the git cache is up to date
490
501
  cache
491
502
  checkout
@@ -506,7 +517,7 @@ module Bundler
506
517
  end
507
518
 
508
519
  def load_spec_files
509
- super
520
+ super if cache_path.exist?
510
521
  rescue PathError
511
522
  raise PathError, "#{to_s} is not checked out. Please run `bundle install`"
512
523
  end
@@ -79,16 +79,8 @@ module Bundler
79
79
  SpecSet.new(materialized.compact)
80
80
  end
81
81
 
82
- def names
83
- lookup.keys
84
- end
85
-
86
- def select!(names)
87
- @lookup = nil
88
- @sorted = nil
89
-
90
- @specs.delete_if { |s| !names.include?(s.name) }
91
- self
82
+ def merge(set)
83
+ SpecSet.new(sorted + set.to_a)
92
84
  end
93
85
 
94
86
  private
data/lib/bundler/ui.rb CHANGED
@@ -15,18 +15,19 @@ module Bundler
15
15
  class Shell < UI
16
16
  def initialize(shell)
17
17
  @shell = shell
18
+ @quiet = false
18
19
  end
19
20
 
20
21
  def debug(msg)
21
- @shell.say(msg) if ENV['DEBUG']
22
+ @shell.say(msg) if ENV['DEBUG'] && !@quiet
22
23
  end
23
24
 
24
25
  def info(msg)
25
- @shell.say(msg)
26
+ @shell.say(msg) if !@quiet
26
27
  end
27
28
 
28
29
  def confirm(msg)
29
- @shell.say(msg, :green)
30
+ @shell.say(msg, :green) if !@quiet
30
31
  end
31
32
 
32
33
  def warn(msg)
@@ -36,6 +37,10 @@ module Bundler
36
37
  def error(msg)
37
38
  @shell.say(msg, :red)
38
39
  end
40
+
41
+ def be_quiet!
42
+ @quiet = true
43
+ end
39
44
  end
40
45
 
41
46
  class RGProxy < Gem::SilentUI
@@ -52,4 +57,4 @@ module Bundler
52
57
  end
53
58
  end
54
59
  end
55
- end
60
+ end
@@ -1,3 +1,6 @@
1
1
  module Bundler
2
- VERSION = "1.0.0.beta.1"
2
+ # We're doing this because we might write tests that deal
3
+ # with other versions of bundler and we are unsure how to
4
+ # handle this better.
5
+ VERSION = "1.0.0.beta.2" unless defined?(::Bundler::VERSION)
3
6
  end
metadata CHANGED
@@ -7,8 +7,8 @@ version: !ruby/object:Gem::Version
7
7
  - 0
8
8
  - 0
9
9
  - beta
10
- - 1
11
- version: 1.0.0.beta.1
10
+ - 2
11
+ version: 1.0.0.beta.2
12
12
  platform: ruby
13
13
  authors:
14
14
  - Carl Lerche
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2010-06-08 00:00:00 -04:00
21
+ date: 2010-06-28 00:00:00 -07:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency