bundler 0.9.26 → 1.0.0.beta.1

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.

@@ -1,3 +1,10 @@
1
+ ## 0.10.0
2
+
3
+ - No `bundle lock` command. Locking happens automatically on install or update
4
+ - No .bundle/environment.rb. Require 'bundler/setup' instead.
5
+ - $BUNDLE_HOME defaults to $GEM_HOME instead of ~/.bundle
6
+ - Remove lockfiles generated by 0.9
7
+
1
8
  ## 0.9.26
2
9
 
3
10
  Features:
data/README.md CHANGED
@@ -1,3 +1,5 @@
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`.
2
+
1
3
  ## Bundler : A gem to bundle gems
2
4
 
3
5
  Bundler is a tool that manages gem dependencies for your ruby application. It
@@ -120,7 +122,7 @@ When deploying to a server that is memory-constrained, like Dreamhost, you shoul
120
122
 
121
123
  ### Other questions
122
124
 
123
- Any remaining questions may be asked via IRC in [#carlhuda](irc://irc.freenode.net/carlhuda) on Freenode, or via email on the [Bundler mailing list](http://groups.google.com/group/ruby-bundler).
125
+ Any remaining questions may be asked via IRC in [#bundler](irc://irc.freenode.net/bundler) on Freenode, or via email on the [Bundler mailing list](http://groups.google.com/group/ruby-bundler).
124
126
 
125
127
  ## Reporting bugs
126
128
 
data/ROADMAP.md CHANGED
@@ -1,51 +1,36 @@
1
- We will be releasing one more point release (0.10.x) followed by 1.0. While
2
- the following reflects our current thinking, critical bugs may alter it
3
- somewhat.
4
-
5
- # 0.10
1
+ # 1.0
6
2
 
7
3
  - No breaking changes to the Gemfile are expected
8
4
  - We expect to modify the format of Gemfile.lock.
9
- - This should be the final change; it will not change for 1.0
10
- - The Gemfile.lock generated by 0.9 will continue to work until 1.0
11
- - If you use Bundler 0.10, we will transparently update the format
12
- - This means: you will not be able to upgrade a locked app
13
- directly from 0.9 to 1.0.
14
- - Bundler 0.10 will automatically generate Gemfile.lock when any
5
+ - This should be the final change
6
+ - This means you will not be able to upgrade a locked app
7
+ directly from 0.9 to 1.0.
8
+ - Bundler will automatically generate Gemfile.lock when any
15
9
  resolve is successful.
16
- - bundle install will conservatively update Gemfile.lock from the
10
+ - This means the bundle lock command will no longer be needed.
11
+ - Bundler will conservatively update Gemfile.lock from the
17
12
  last successful resolve if the Gemfile has been modified since
18
13
  the last use of bundler.
19
14
  - This means that adding a new gem to the Gemfile that does not
20
- conflict with existing gems will not force an update of other
21
- gems.
15
+ conflict with existing gems will not force an update of other
16
+ gems.
22
17
  - This also means that we will not force an update to previously
23
- resolved dependencies as long as they are compatible with some
24
- valid version of the new dependency.
18
+ resolved dependencies as long as they are compatible with some
19
+ valid version of the new dependency.
25
20
  - When removing a gem, bundle install will simply remove it, without
26
- recalculating all dependencies.
21
+ recalculating all dependencies.
27
22
  - We will be adding `bundle update` for the case where you -do-
28
23
  wish to re-resolve all dependencies and update everything to the
29
24
  latest version.
30
25
  - bundle update will also take a gem name, if you want to force
31
- an update to just a single gem (and its dependencies).
32
- - Add a way to install dependencies that require build options
33
- - Add a way to specify groups that are opt-in at install-time,
34
- rather than opt-out.
35
- - Some additional features that we have tagged for 0.10. For up
36
- to date information, please visit
37
- http://github.com/carlhuda/bundler/issues/labels/0.10
38
-
39
- # 1.0
40
-
41
- - No breaking changes to the Gemfile are expected
42
- - No breaking changes to the Gemfile.lock are expected
43
- - No major changes to the workflow are expected
44
- - Reduce open bug count to 0
26
+ an update to just a single gem (and its dependencies).
27
+ - There will be a way to install dependencies that require build options
28
+ - We will add groups that are opt-in at install-time, rather than opt-out.
29
+ - We will reduce open bug count to 0 for the final 1.0 release.
45
30
  - Some additional features that require more thought. For details,
46
31
  see http://github.com/carlhuda/bundler/issues/labels/1.0
47
32
 
48
- # No Breaking changes
33
+ # 1.1
49
34
 
50
- We expect no breaking changes of the Gemfile, Gemfile.lock, or
51
- basic workflow for 1.x releases.
35
+ - Stop upgrading 0.9 lockfiles
36
+ - Delete vestigial gems installed into ~/.bundle/ by 0.9
data/TODO.md ADDED
@@ -0,0 +1,16 @@
1
+ ## Bundler TODO list
2
+
3
+ - Check to make sure ~/.bundler/bin is in $PATH
4
+ - Cache Git repositories
5
+ - Interactive mode for bundle (install) to work out conflicts
6
+ - bundle irb / bundle ruby / bundle [whatever] -> bundle exec
7
+ - Make bundle (install) work when sudo might be needed
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
@@ -5,12 +5,17 @@ require 'bundler/rubygems_ext'
5
5
  require 'bundler/version'
6
6
 
7
7
  module Bundler
8
+ ORIGINAL_ENV = ENV.to_hash
9
+
8
10
  autoload :Definition, 'bundler/definition'
9
11
  autoload :Dependency, 'bundler/dependency'
10
12
  autoload :Dsl, 'bundler/dsl'
11
13
  autoload :Environment, 'bundler/environment'
14
+ autoload :Graph, 'bundler/graph'
12
15
  autoload :Index, 'bundler/index'
13
16
  autoload :Installer, 'bundler/installer'
17
+ autoload :LazySpecification, 'bundler/lazy_specification'
18
+ autoload :LockfileParser, 'bundler/lockfile_parser'
14
19
  autoload :RemoteSpecification, 'bundler/remote_specification'
15
20
  autoload :Resolver, 'bundler/resolver'
16
21
  autoload :Runtime, 'bundler/runtime'
@@ -21,9 +26,6 @@ module Bundler
21
26
  autoload :Specification, 'bundler/shared_helpers'
22
27
  autoload :UI, 'bundler/ui'
23
28
 
24
- GEM_LOADED = true
25
- ORIGINAL_ENV = ENV.to_hash
26
-
27
29
  class BundlerError < StandardError
28
30
  def self.status_code(code = nil)
29
31
  return @code unless code
@@ -37,7 +39,6 @@ module Bundler
37
39
 
38
40
  class GemfileNotFound < BundlerError; status_code(10) ; end
39
41
  class GemNotFound < BundlerError; status_code(7) ; end
40
- class VersionConflict < BundlerError; status_code(6) ; end
41
42
  class GemfileError < BundlerError; status_code(4) ; end
42
43
  class GemfileChanged < GemfileError; status_code(4) ; end
43
44
  class PathError < BundlerError; status_code(13) ; end
@@ -45,8 +46,23 @@ module Bundler
45
46
  class GemspecError < BundlerError; status_code(14) ; end
46
47
  class DeprecatedMethod < BundlerError; status_code(12) ; end
47
48
  class DeprecatedOption < BundlerError; status_code(12) ; end
49
+ class GemspecError < BundlerError; status_code(14) ; end
48
50
  class InvalidOption < BundlerError; status_code(15) ; end
49
51
 
52
+ class VersionConflict < BundlerError
53
+ attr_reader :conflicts
54
+
55
+ def initialize(conflicts, msg = nil)
56
+ super(msg)
57
+ @conflicts = conflicts
58
+ end
59
+
60
+ status_code(6)
61
+ end
62
+
63
+ # Internal errors, should be rescued
64
+ class InvalidSpecSet < StandardError; end
65
+
50
66
  class << self
51
67
  attr_writer :ui, :bundle_path
52
68
 
@@ -63,12 +79,20 @@ module Bundler
63
79
 
64
80
  def bundle_path
65
81
  @bundle_path ||= begin
66
- path = settings[:path] || "#{Gem.user_home}/.bundle/#{Gem.ruby_engine}/#{Gem::ConfigMap[:ruby_version]}"
82
+ path = settings[:path] || Gem.dir
67
83
  Pathname.new(path).expand_path(root)
68
84
  end
69
85
  end
70
86
 
71
- def gem_setup(*groups)
87
+ def bin_path
88
+ @bin_path ||= begin
89
+ path = settings[:bin] || "#{Gem.user_home}/.bundle/bin"
90
+ FileUtils.mkdir_p(path)
91
+ Pathname.new(path).expand_path
92
+ end
93
+ end
94
+
95
+ def setup(*groups)
72
96
  return @setup if @setup
73
97
 
74
98
  if groups.empty?
@@ -83,35 +107,26 @@ module Bundler
83
107
  unloaded.any? ? load.setup(*unloaded) : load
84
108
  end
85
109
  end
86
- alias setup gem_setup unless defined?(Bundler::ENV_LOADED)
87
110
 
88
- def gem_require(*groups)
111
+ def require(*groups)
89
112
  setup(*groups).require(*groups)
90
113
  end
91
- alias require gem_require unless defined?(Bundler::ENV_LOADED)
92
114
 
93
115
  def load
94
- @load ||= begin
95
- if !update_env_file?
96
- Kernel.require env_file
97
- Bundler
98
- else
99
- runtime
100
- end
101
- end
116
+ @load ||= Runtime.new(root, definition)
102
117
  end
103
118
 
104
- def runtime
105
- @runtime ||= Runtime.new(root, definition)
119
+ def environment
120
+ Bundler::Environment.new(root, definition)
106
121
  end
107
122
 
108
- def definition
109
- configure
110
- lockfile = root.join("Gemfile.lock")
111
- if lockfile.exist?
112
- Definition.from_lock(lockfile)
113
- else
114
- Definition.from_gemfile(default_gemfile)
123
+ def definition(unlock = nil)
124
+ @definition = nil if unlock
125
+ @definition ||= begin
126
+ configure
127
+ upgrade_lockfile
128
+ lockfile = root.join("Gemfile.lock")
129
+ Definition.build(default_gemfile, lockfile, unlock)
115
130
  end
116
131
  end
117
132
 
@@ -132,15 +147,19 @@ module Bundler
132
147
  end
133
148
 
134
149
  def root
135
- default_gemfile.dirname
150
+ default_gemfile.dirname.expand_path
136
151
  end
137
152
 
138
- def settings
139
- @settings ||= Settings.new(root)
153
+ def app_cache
154
+ root.join("vendor/cache")
155
+ end
156
+
157
+ def tmp
158
+ "#{Gem.user_home}/.bundler/tmp"
140
159
  end
141
160
 
142
- def env_file
143
- SharedHelpers.env_file
161
+ def settings
162
+ @settings ||= Settings.new(root)
144
163
  end
145
164
 
146
165
  def with_clean_env
@@ -155,6 +174,22 @@ module Bundler
155
174
  SharedHelpers.default_gemfile
156
175
  end
157
176
 
177
+ WINDOWS = Config::CONFIG["host_os"] =~ %r!(msdos|mswin|djgpp|mingw)!
178
+ NULL = WINDOWS ? "NUL" : "/dev/null"
179
+
180
+ def requires_sudo?
181
+ case
182
+ when File.writable?(bundle_path) ||
183
+ `which sudo 2>#{NULL}`.empty? ||
184
+ File.owned?(bundle_path)
185
+ false
186
+ else
187
+ true
188
+ end
189
+ rescue Errno::ENOENT
190
+ false
191
+ end
192
+
158
193
  private
159
194
 
160
195
  def configure_gem_home_and_path
@@ -170,17 +205,28 @@ module Bundler
170
205
  Gem.clear_paths
171
206
  end
172
207
 
173
- def update_env_file?
174
- if env_file.exist?
175
- outdated = (env_file.read(100) !~ /Bundler #{Bundler::VERSION}/)
176
- writable = env_file.writable?
177
- if outdated && !writable
178
- STDERR.puts "Cannot write to outdated .bundle/environment.rb to update it"
179
- end
180
- outdated && writable
181
- else
182
- true
208
+ def upgrade_lockfile
209
+ lockfile = root.join("Gemfile.lock")
210
+ if lockfile.exist? && lockfile.read(3) == "---"
211
+ Bundler.ui.warn "Detected Gemfile.lock generated by 0.9, deleting..."
212
+ lockfile.rmtree
213
+ # lock = YAML.load_file(lockfile)
214
+ #
215
+ # source_uris = lock["sources"].map{|s| s["Rubygems"]["uri"] }
216
+ # sources = [Bundler::Source::Rubygems.new({"remotes" => source_uris})]
217
+ #
218
+ # deps = lock["dependencies"].map do |name, opts|
219
+ # version = opts.delete("version")
220
+ # Bundler::Dependency.new(name, version, opts)
221
+ # end
222
+ #
223
+ # definition = Bundler::Definition.new(nil, deps, sources, {})
224
+ #
225
+ # File.open(lockfile, 'w') do |f|
226
+ # f.write definition.to_lock
227
+ # end
183
228
  end
184
229
  end
230
+
185
231
  end
186
232
  end
@@ -7,9 +7,22 @@ Gem.configuration
7
7
 
8
8
  module Bundler
9
9
  class CLI < Thor
10
+ def initialize(*)
11
+ super
12
+ Bundler.ui = UI::Shell.new(shell)
13
+ Gem::DefaultUserInteraction.ui = UI::RGProxy.new(Bundler.ui)
14
+ end
15
+
10
16
  check_unknown_options! unless ARGV.include?("exec")
11
17
 
18
+ default_task :install
19
+
12
20
  desc "init", "Generates a Gemfile into the current working directory"
21
+ long_desc <<-D
22
+ Init generates a default Gemfile in the current working directory. When adding a
23
+ Gemfile to a gem with a gemspec, the --gemspec option will automatically add each
24
+ dependency listed in the gemspec file to the newly created Gemfile.
25
+ D
13
26
  method_option "gemspec", :type => :string, :banner => "Use the specified .gemspec to create the Gemfile"
14
27
  def init
15
28
  opts = options.dup
@@ -36,44 +49,46 @@ module Bundler
36
49
  end
37
50
  end
38
51
 
39
- def initialize(*)
40
- super
41
- Bundler.ui = UI::Shell.new(shell)
42
- Gem::DefaultUserInteraction.ui = UI::RGProxy.new(Bundler.ui)
43
- end
44
-
45
52
  desc "check", "Checks if the dependencies listed in Gemfile are satisfied by currently installed gems"
53
+ long_desc <<-D
54
+ Check searches the local machine for each of the gems requested in the Gemfile. If
55
+ all gems are found, Bundler prints a success message and exits with a status of 0.
56
+ If not, the first missing gem is listed and Bundler exits status 1.
57
+ D
46
58
  def check
47
- env = Bundler.runtime
48
- # Check top level dependencies
49
- missing = env.dependencies.select { |d| env.index.search(d).empty? }
50
- if missing.any?
51
- Bundler.ui.error "The following dependencies are missing"
52
- missing.each do |d|
53
- Bundler.ui.error " * #{d}"
54
- end
59
+ not_installed = Bundler.definition.missing_specs
60
+
61
+ if not_installed.any?
62
+ Bundler.ui.error "The following gems are missing"
63
+ not_installed.each { |s| Bundler.ui.error " * #{s.name} (#{s.version})" }
55
64
  Bundler.ui.warn "Install missing gems with `bundle install`"
56
65
  exit 1
57
66
  else
58
- not_installed = env.requested_specs.select { |spec| !spec.loaded_from }
59
-
60
- if not_installed.any?
61
- not_installed.each { |s| Bundler.ui.error "#{s.name} (#{s.version}) is cached, but not installed" }
62
- Bundler.ui.warn "Install missing gems with `bundle install`"
63
- exit 1
64
- else
65
- Bundler.ui.info "The Gemfile's dependencies are satisfied"
66
- end
67
+ Bundler.ui.info "The Gemfile's dependencies are satisfied"
67
68
  end
68
69
  end
69
70
 
70
71
  desc "install", "Install the current environment to the system"
71
- method_option "without", :type => :array, :banner => "Exclude gems that are part of the specified named group."
72
- method_option "relock", :type => :boolean, :banner => "Unlock, install the gems, and relock."
73
- method_option "disable-shared-gems", :type => :boolean, :banner => "Do not use any shared gems, such as the system gem repository."
74
- method_option "gemfile", :type => :string, :banner => "Use the specified gemfile instead of Gemfile"
75
- method_option "no-cache", :type => :boolean, :banner => "Don't update the existing gem cache."
76
- method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache."
72
+ long_desc <<-D
73
+ Install will install all of the gems in the current bundle, making them available
74
+ for use. In a freshly checked out repository, this command will give you the same
75
+ gem versions as the last person who updated the Gemfile and ran `bundle update`.
76
+
77
+ Passing [DIR] to install (e.g. vendor) will cause the unpacked gems to be installed
78
+ into the [DIR] directory rather than into system gems.
79
+
80
+ If the bundle has already been installed, bundler will tell you so and then exit.
81
+ D
82
+ method_option "without", :type => :array, :banner =>
83
+ "Exclude gems that are part of the specified named group."
84
+ method_option "disable-shared-gems", :type => :boolean, :banner =>
85
+ "Do not use any shared gems, such as the system gem repository."
86
+ method_option "gemfile", :type => :string, :banner =>
87
+ "Use the specified gemfile instead of Gemfile"
88
+ method_option "no-prune", :type => :boolean, :banner =>
89
+ "Don't remove stale gems from the cache."
90
+ method_option "no-cache", :type => :boolean, :banner =>
91
+ "Don't update the existing gem cache."
77
92
  def install(path = nil)
78
93
  opts = options.dup
79
94
  opts[:without] ||= []
@@ -82,62 +97,61 @@ module Bundler
82
97
  # Can't use Bundler.settings for this because settings needs gemfile.dirname
83
98
  ENV['BUNDLE_GEMFILE'] = opts[:gemfile] if opts[:gemfile]
84
99
  Bundler.settings[:path] = path if path
85
- Bundler.settings[:disable_shared_gems] = '1' if options["disable-shared-gems"]
100
+ Bundler.settings[:disable_shared_gems] = '1' if options["disable-shared-gems"] || path
86
101
  Bundler.settings.without = opts[:without]
87
102
 
88
- remove_lockfiles if options[:relock]
89
-
90
- begin
91
- Installer.install(Bundler.root, Bundler.definition, opts)
92
- rescue GemfileChanged
93
- raise GemfileChanged, "You changed your Gemfile after locking. " +
94
- "Please run `bundle install --relock`."
95
- end
96
-
97
- lock if options[:relock]
98
- cache if Bundler.root.join("vendor/cache").exist? && !options[:no_cache]
103
+ Installer.install(Bundler.root, Bundler.definition, opts)
104
+ cache if Bundler.root.join("vendor/cache").exist?
99
105
  Bundler.ui.confirm "Your bundle is complete! " +
100
106
  "Use `bundle show [gemname]` to see where a bundled gem is installed."
101
107
  rescue GemNotFound => e
102
- if Bundler.definition.sources.empty?
108
+ if Bundler.definition.no_sources?
103
109
  Bundler.ui.warn "Your Gemfile doesn't have any sources. You can add one with a line like 'source :gemcutter'"
104
110
  end
105
111
  raise e
106
112
  end
107
113
 
108
- desc "lock", "Locks the bundle to the current set of dependencies, including all child dependencies."
109
- def lock
110
- if locked?
111
- Bundler.ui.info("Your bundle is already locked, relocking.")
112
- remove_lockfiles
114
+ desc "update", "update the current environment"
115
+ long_desc <<-D
116
+ Update will install the newest versions of the gems listed in the Gemfile. Use
117
+ update when you have changed the Gemfile, or if you want to get the newest
118
+ possible versions of the gems in the bundle.
119
+ D
120
+ method_option "source", :type => :array, :banner => "Update a specific source (and all gems associated with it)"
121
+ def update(*gems)
122
+ sources = Array(options[:source])
123
+
124
+ if gems.empty? && sources.empty?
125
+ # We're doing a full update
126
+ FileUtils.rm Bundler.root.join("Gemfile.lock")
127
+ else
128
+ Bundler.definition(:gems => gems, :sources => sources)
113
129
  end
114
130
 
115
- Bundler.runtime.lock
116
- Bundler.ui.confirm("Your bundle is now locked. " +
117
- "Use `bundle show [gemname]` to list the gems in the environment.")
118
- rescue GemNotFound, VersionConflict => e
119
- Bundler.ui.error(e.message)
120
- Bundler.ui.warn "Run `bundle install` to install missing gems."
121
- exit 128
131
+ Installer.install Bundler.root, Bundler.definition
132
+ end
133
+
134
+ desc "lock", "Locks the bundle to the current set of dependencies, including all child dependencies."
135
+ def lock
136
+ Bundler.ui.warn "Lock is deprecated. Your bundle is now locked whenever you run `bundle install`."
122
137
  end
123
138
 
124
139
  desc "unlock", "Unlock the bundle. This allows gem versions to be changed."
125
140
  def unlock
126
- if locked?
127
- remove_lockfiles
128
- Bundler.ui.info("Your bundle is now unlocked. The dependencies may be changed.")
129
- else
130
- Bundler.ui.info("Your bundle is not currently locked.")
131
- end
141
+ Bundler.ui.warn "Unlock is deprecated. To update to newer gem versions, use `bundle update`."
132
142
  end
133
143
 
134
144
  desc "show [GEM]", "Shows all gems that are part of the bundle, or the path to a given gem"
145
+ long_desc <<-D
146
+ Show lists the names and versions of all gems that are required by your Gemfile.
147
+ Calling show with [GEM] will list the exact location of that gem on your machine.
148
+ D
135
149
  def show(gem_name = nil)
136
150
  if gem_name
137
151
  Bundler.ui.info locate_gem(gem_name)
138
152
  else
139
153
  Bundler.ui.info "Gems included by the bundle:"
140
- Bundler.runtime.specs.sort_by { |s| s.name }.each do |s|
154
+ Bundler.load.specs.sort_by { |s| s.name }.each do |s|
141
155
  Bundler.ui.info " * #{s.name} (#{s.version}#{s.git_version})"
142
156
  end
143
157
  end
@@ -147,8 +161,8 @@ module Bundler
147
161
  desc "cache", "Cache all the gems to vendor/cache"
148
162
  method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache."
149
163
  def cache
150
- Bundler.runtime.cache
151
- Bundler.runtime.prune_cache unless options[:no_prune]
164
+ Bundler.load.cache
165
+ Bundler.load.prune_cache unless options[:no_prune]
152
166
  rescue GemNotFound => e
153
167
  Bundler.ui.error(e.message)
154
168
  Bundler.ui.warn "Run `bundle install` to install missing gems."
@@ -157,13 +171,25 @@ module Bundler
157
171
 
158
172
  desc "package", "Locks and then caches all of the gems into vendor/cache"
159
173
  method_option "no-prune", :type => :boolean, :banner => "Don't remove stale gems from the cache."
174
+ long_desc <<-D
175
+ The package command will copy the .gem files for every gem in the bundle into the
176
+ directory ./vendor/cache. If you then check that directory into your source
177
+ control repository, others who check out your source will be able to install the
178
+ bundle without having to download any additional gems.
179
+ D
160
180
  def package
161
- lock
181
+ install
182
+ # TODO: move cache contents here now that all bundles are locked
162
183
  cache
163
184
  end
164
185
  map %w(pack) => :package
165
186
 
166
187
  desc "exec", "Run the command in context of the bundle"
188
+ long_desc <<-D
189
+ Exec runs a command, providing it access to the gems in the bundle. While using
190
+ bundle exec you can require and call the bundled gems as if they were installed
191
+ into the systemwide Rubygems repository.
192
+ D
167
193
  def exec(*)
168
194
  ARGV.delete("exec")
169
195
 
@@ -185,7 +211,7 @@ module Bundler
185
211
 
186
212
  begin
187
213
  # Run
188
- Kernel.exec *ARGV
214
+ Kernel.exec(*ARGV)
189
215
  rescue Errno::EACCES
190
216
  Bundler.ui.error "bundler: not executable: #{ARGV.first}"
191
217
  rescue Errno::ENOENT
@@ -222,19 +248,35 @@ module Bundler
222
248
  end
223
249
  map %w(-v --version) => :version
224
250
 
225
- private
251
+ 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."
255
+ def viz
256
+ output_file = File.expand_path(options[:file])
257
+ graph = Graph.new( Bundler.load )
226
258
 
227
- def locked?
228
- File.exist?("#{Bundler.root}/Gemfile.lock") || File.exist?("#{Bundler.root}/.bundle/environment.rb")
259
+ begin
260
+ graph.viz(output_file, options[:version], options[:requirements])
261
+ Bundler.ui.info output_file
262
+ rescue LoadError => e
263
+ Bundler.ui.error e.inspect
264
+ Bundler.ui.warn "Make sure you have the graphviz ruby gem. You can install it with:"
265
+ Bundler.ui.warn "`gem install ruby-graphviz`"
266
+ rescue StandardError => e
267
+ if e.message =~ /GraphViz not installed or dot not in PATH/
268
+ Bundler.ui.error e.message
269
+ Bundler.ui.warn "The ruby graphviz gem requires GraphViz to be installed"
270
+ else
271
+ raise
272
+ end
273
+ end
229
274
  end
230
275
 
231
- def remove_lockfiles
232
- FileUtils.rm_f "#{Bundler.root}/Gemfile.lock"
233
- FileUtils.rm_f "#{Bundler.root}/.bundle/environment.rb"
234
- end
276
+ private
235
277
 
236
278
  def locate_gem(name)
237
- spec = Bundler.runtime.specs.find{|s| s.name == name }
279
+ spec = Bundler.load.specs.find{|s| s.name == name }
238
280
  raise GemNotFound, "Could not find gem '#{name}' in the current bundle." unless spec
239
281
  spec.full_gem_path
240
282
  end