bundler 0.9.0.pre3 → 0.9.0.pre4

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.

@@ -0,0 +1,152 @@
1
+ ## Bundler : A gem to bundle gems
2
+
3
+ Github: http://github.com/wycats/bundler
4
+ Mailing list: http://groups.google.com/group/ruby-bundler
5
+ IRC: #carlhuda on freenode
6
+
7
+ ## Intro
8
+
9
+ Bundler is a tool that manages gem dependencies for your ruby application. It
10
+ takes a gem manifest file and is able to fetch, download, and install the gems
11
+ and all child dependencies specified in this manifest. It can manage any update
12
+ to the gem manifest file and update the bundle's gems accordingly. It also lets
13
+ you run any ruby code in context of the bundle's gem environment.
14
+
15
+ ## Installation
16
+
17
+ Bundler has no dependencies besides Ruby and RubyGems. Just clone the git
18
+ repository and install the gem with the following rake task:
19
+
20
+ rake install
21
+
22
+ You can also install the gem with
23
+
24
+ gem install bundler --prerelease
25
+
26
+ ## Usage
27
+
28
+ The first thing to do is create a gem manifest file named `Gemfile` at the
29
+ root directory of your application. This can quickly be done by running
30
+ `bundle init` in the directory that you wish the Gemfile to be created in.
31
+
32
+ ### Gemfile
33
+
34
+ This is where you specify all of your application's dependencies. The
35
+ following is an example. For more information, refer to
36
+ Bundler::Dsl.
37
+
38
+ # Add :gemcutter as a source that Bundler will use
39
+ # to find gems listed in the manifest. At least one source
40
+ # should be listed. URLs maybe also be used, such as
41
+ # http://gems.github.com.
42
+ #
43
+ source :gemcutter
44
+
45
+ # Specify a dependency on rails. When bundler downloads gems,
46
+ # it will download rails as well as all of rails' dependencies
47
+ # (such as activerecord, actionpack, etc...)
48
+ #
49
+ # At least one dependency must be specified
50
+ #
51
+ gem "rails"
52
+
53
+ # Specify a dependency on rack v.1.0.0. The version is optional.
54
+ # If present, it can be specified the same way as with rubygems'
55
+ # #gem method.
56
+ #
57
+ gem "rack", "1.0.0"
58
+
59
+ ### Installing gems
60
+
61
+ Once the manifest file has been created, the next step is to install all
62
+ the gems needed to satisfy the Gemfile's dependencies. The `bundle install`
63
+ command will do this.
64
+
65
+ This command will load the Gemfile, resolve all the dependencies, download
66
+ all gems that are missing, and install them to the system's RubyGems
67
+ repository. Every time an update is made to the Gemfile, run `bundle install`
68
+ again to get the new gems installed.
69
+
70
+ ### Locking dependencies
71
+
72
+ By default, bundler will only ensure that the activated gems satisfy the
73
+ Gemfile's dependencies. If you install a newer version of a gem and it
74
+ satisfies the dependencies, it will be used instead of the older one.
75
+
76
+ The command `bundle lock` will lock the bundle to the current set of
77
+ resolved gems. This ensures that, until the lock file is removed, that
78
+ bundle install and Bundle.setup will always activate the same gems.
79
+
80
+ ### Running the application
81
+
82
+ Bundler must be required and setup before anything else is required. This
83
+ is because it will configure all the load paths and manage rubygems for your.
84
+ To do this, include the following at the beginning of your code.
85
+
86
+ begin
87
+ # Require the preresolved locked set of gems.
88
+ require File.expand_path('../vendor/environment', __FILE__)
89
+ rescue LoadError
90
+ # Fallback on doing the resolve at runtime.
91
+ require "rubygems"
92
+ require "bundler"
93
+ Bundler.setup
94
+ end
95
+
96
+ # Your application requires come here
97
+
98
+ The `bundle exec` command provides a way to run arbitrary ruby code in
99
+ context of the bundle. For example:
100
+
101
+ bundle exec ruby my_ruby_script.rb
102
+
103
+ To enter a shell that will run all gem executables (such as rake, rails,
104
+ etc... ) use `bundle exec bash` (replacing bash for whatever your favorite
105
+ shell is).
106
+
107
+ ### Packing the bundle's gems
108
+
109
+ When sharing or deploying an application, it might be useful to include
110
+ everything necessary to install gem dependencies. `bundle pack` will
111
+ copy .gem files for all of the bundle's dependencies into vendor/cache.
112
+ This way, bundle install can always work no matter what the state of the
113
+ remote sources.
114
+
115
+ ## Gem resolution
116
+
117
+ One of the most important things that the bundler does is do a
118
+ dependency resolution on the full list of gems that you specify, all
119
+ at once. This differs from the one-at-a-time dependency resolution that
120
+ Rubygems does, which can result in the following problem:
121
+
122
+ # On my system:
123
+ # activesupport 3.0.pre
124
+ # activesupport 2.3.4
125
+ # activemerchant 1.4.2
126
+ # rails 2.3.4
127
+ #
128
+ # activemerchant 1.4.2 depends on activesupport >= 2.3.2
129
+
130
+ gem "activemerchant", "1.4.2"
131
+ # results in activating activemerchant, as well as
132
+ # activesupport 3.0.pre, since it is >= 2.3.2
133
+
134
+ gem "rails", "2.3.4"
135
+ # results in:
136
+ # can't activate activesupport (= 2.3.4, runtime)
137
+ # for ["rails-2.3.4"], already activated
138
+ # activesupport-3.0.pre for ["activemerchant-1.4.2"]
139
+
140
+ This is because activemerchant has a broader dependency, which results
141
+ in the activation of a version of activesupport that does not satisfy
142
+ a more narrow dependency.
143
+
144
+ Bundler solves this problem by evaluating all dependencies at once,
145
+ so it can detect that all gems *together* require activesupport "2.3.4".
146
+
147
+ ## Reporting bugs
148
+
149
+ Please report all bugs on the github issue tracker for the project located
150
+ at:
151
+
152
+ http://github.com/wycats/bundler/issues/
data/bin/bundle CHANGED
@@ -1,3 +1,8 @@
1
1
  require 'bundler/cli'
2
2
 
3
- Bundler::CLI.start
3
+ begin
4
+ Bundler::CLI.start
5
+ rescue Bundler::BundlerError => e
6
+ puts e.message
7
+ exit e.status_code
8
+ end
@@ -4,7 +4,7 @@ require 'yaml'
4
4
  require 'bundler/rubygems'
5
5
 
6
6
  module Bundler
7
- VERSION = "0.9.0.pre3"
7
+ VERSION = "0.9.0.pre4"
8
8
 
9
9
  autoload :Definition, 'bundler/definition'
10
10
  autoload :Dependency, 'bundler/dependency'
@@ -18,67 +18,108 @@ module Bundler
18
18
  autoload :Specification, 'bundler/specification'
19
19
  autoload :UI, 'bundler/ui'
20
20
 
21
- class GemfileNotFound < StandardError; end
22
- class GemNotFound < StandardError; end
23
- class VersionConflict < StandardError; end
24
- class GemfileError < StandardError; end
21
+ class BundlerError < StandardError
22
+ def self.status_code(code = nil)
23
+ return @code unless code
24
+ @code = code
25
+ end
25
26
 
26
- def self.ui
27
- @ui ||= UI.new
27
+ def status_code
28
+ self.class.status_code
29
+ end
28
30
  end
29
31
 
30
- def self.ui=(ui)
31
- @ui = ui
32
- end
32
+ class GemfileNotFound < BundlerError; status_code(10) ; end
33
+ class GemNotFound < BundlerError; status_code(7) ; end
34
+ class VersionConflict < BundlerError; status_code(6) ; end
35
+ class GemfileError < BundlerError; status_code(4) ; end
33
36
 
34
- def self.setup(*groups)
35
- gemfile = default_gemfile
36
- load(gemfile).setup(*groups)
37
- end
37
+ class << self
38
+ attr_writer :ui, :bundle_path
38
39
 
39
- def self.load(gemfile = default_gemfile)
40
- root = Pathname.new(gemfile).dirname
41
- Environment.new root, definition(gemfile)
42
- end
40
+ def configure
41
+ @configured ||= begin
42
+ point_gem_home(env[:bundle_path])
43
+ true
44
+ end
45
+ end
43
46
 
44
- def self.definition(gemfile = default_gemfile)
45
- root = Pathname.new(gemfile).dirname
46
- lockfile = root.join("vendor/lock.yml")
47
- if lockfile.exist?
48
- Definition.from_lock(lockfile)
49
- else
50
- Definition.from_gemfile(gemfile)
47
+ def ui
48
+ @ui ||= UI.new
51
49
  end
52
- end
53
50
 
54
- def self.home
55
- Pathname.new(Gem.dir).join("bundler")
56
- end
51
+ def bundle_path
52
+ @bundle_path ||= Pathname.new(env[:bundle_path] || Gem.dir)
53
+ end
57
54
 
58
- def self.install_path
59
- home.join("gems")
60
- end
55
+ def setup(*groups)
56
+ gemfile = default_gemfile
57
+ load(gemfile).setup(*groups)
58
+ end
61
59
 
62
- def self.cache
63
- home.join("cache")
64
- end
60
+ def load(gemfile = default_gemfile)
61
+ root = Pathname.new(gemfile).dirname
62
+ Environment.new root, definition(gemfile)
63
+ end
65
64
 
66
- def self.root
67
- default_gemfile.dirname
68
- end
65
+ def definition(gemfile = default_gemfile)
66
+ configure
67
+ root = Pathname.new(gemfile).dirname
68
+ lockfile = root.join("Gemfile.lock")
69
+ if lockfile.exist?
70
+ Definition.from_lock(lockfile)
71
+ else
72
+ Definition.from_gemfile(gemfile)
73
+ end
74
+ end
69
75
 
70
- private
76
+ def home
77
+ Pathname.new(bundle_path).join("bundler")
78
+ end
71
79
 
72
- def self.default_gemfile
73
- current = Pathname.new(Dir.pwd)
80
+ def install_path
81
+ home.join("gems")
82
+ end
74
83
 
75
- until current.root?
76
- filename = current.join("Gemfile")
77
- return filename if filename.exist?
78
- current = current.parent
84
+ def cache
85
+ home.join("cache")
79
86
  end
80
87
 
81
- raise GemfileNotFound, "The default Gemfile was not found"
82
- end
88
+ def root
89
+ default_gemfile.dirname
90
+ end
91
+
92
+ private
93
+
94
+ def default_gemfile
95
+ current = Pathname.new(Dir.pwd)
83
96
 
97
+ until current.root?
98
+ filename = current.join("Gemfile")
99
+ return filename if filename.exist?
100
+ current = current.parent
101
+ end
102
+
103
+ raise GemfileNotFound, "The default Gemfile was not found"
104
+ end
105
+
106
+ def env
107
+ @env ||= begin
108
+ env = {}
109
+ file = "#{root}/.bundleconfig"
110
+ config = File.exist?(file) ? YAML.load_file(file) : {}
111
+ %w(BUNDLE_PATH).each do |key|
112
+ env[key.downcase.to_sym] = config[key] || ENV[key]
113
+ end
114
+ env
115
+ end
116
+ end
117
+
118
+ def point_gem_home(path)
119
+ return unless path
120
+ ENV['GEM_HOME'] = File.expand_path(path, root)
121
+ ENV['GEM_PATH'] = ''
122
+ Gem.clear_paths
123
+ end
124
+ end
84
125
  end
@@ -32,22 +32,18 @@ module Bundler
32
32
 
33
33
  desc "check", "Checks if the dependencies listed in Gemfile are satisfied by currently installed gems"
34
34
  def check
35
- with_rescue do
36
- env = Bundler.load
37
- # Check top level dependencies
38
- missing = env.dependencies.select { |d| env.index.search(d).empty? }
39
- if missing.any?
40
- puts "The following dependencies are missing"
41
- missing.each do |d|
42
- puts " * #{d}"
43
- end
44
- else
45
- env.specs
46
- puts "The Gemfile's dependencies are satisfied"
35
+ env = Bundler.load
36
+ # Check top level dependencies
37
+ missing = env.dependencies.select { |d| env.index.search(d).empty? }
38
+ if missing.any?
39
+ puts "The following dependencies are missing"
40
+ missing.each do |d|
41
+ puts " * #{d}"
47
42
  end
43
+ else
44
+ env.specs
45
+ puts "The Gemfile's dependencies are satisfied"
48
46
  end
49
- rescue VersionConflict => e
50
- puts e.message
51
47
  end
52
48
 
53
49
  desc "install", "Install the current environment to the system"
@@ -58,17 +54,23 @@ module Bundler
58
54
  opts[:without].map! { |g| g.to_sym }
59
55
 
60
56
  Installer.install(Bundler.root, Bundler.definition, opts)
61
- rescue Bundler::GemNotFound => e
62
- puts e.message
63
- exit 1
64
57
  end
65
58
 
66
- desc "lock", "Locks a resolve"
59
+ desc "lock", "Locks the bundle to the current set of dependencies, including all child dependencies."
67
60
  def lock
68
61
  environment = Bundler.load
69
62
  environment.lock
70
63
  end
71
64
 
65
+ desc "show", "Shows all gems that are part of the bundle."
66
+ def show
67
+ environment = Bundler.load
68
+ Bundler.ui.info "Gems included by the bundle:"
69
+ environment.specs.sort_by { |s| s.name }.each do |s|
70
+ Bundler.ui.info " * #{s.name} (#{s.version})"
71
+ end
72
+ end
73
+
72
74
  desc "pack", "Packs all the gems to vendor/cache"
73
75
  def pack
74
76
  environment = Bundler.load
@@ -86,13 +88,5 @@ module Bundler
86
88
  Kernel.exec *ARGV
87
89
  end
88
90
 
89
- private
90
-
91
- def with_rescue
92
- yield
93
- rescue GemfileNotFound => e
94
- puts e.message
95
- exit 1
96
- end
97
91
  end
98
92
  end
@@ -28,14 +28,14 @@ module Bundler
28
28
 
29
29
  def local_index
30
30
  @local_index ||= begin
31
- index = Index.from_installed_gems
31
+ index = Index.new
32
32
 
33
33
  sources.each do |source|
34
34
  next unless source.respond_to?(:local_specs)
35
35
  index = source.local_specs.merge(index)
36
36
  end
37
37
 
38
- index
38
+ Index.from_installed_gems.merge(index)
39
39
  end
40
40
  end
41
41
 
@@ -23,23 +23,23 @@ module Bundler
23
23
  @dependencies << Dependency.new(name, version, options)
24
24
  end
25
25
 
26
- def source(source)
26
+ def source(source, options = {})
27
27
  source = case source
28
28
  when :gemcutter, :rubygems, :rubyforge then Source::Rubygems.new(:uri => "http://gemcutter.org")
29
29
  when String then Source::Rubygems.new(:uri => source)
30
30
  else source
31
31
  end
32
32
 
33
- @sources << source
33
+ options[:prepend] ? @sources.unshift(source) : @sources << source
34
34
  source
35
35
  end
36
36
 
37
37
  def path(path, options = {})
38
- source Source::Path.new(options.merge(:path => path))
38
+ source Source::Path.new(options.merge(:path => path)), options
39
39
  end
40
40
 
41
41
  def git(uri, options = {})
42
- source Source::Git.new(options.merge(:uri => uri))
42
+ source Source::Git.new(options.merge(:uri => uri)), options
43
43
  end
44
44
 
45
45
  def to_definition
@@ -66,17 +66,14 @@ module Bundler
66
66
 
67
67
  opts["group"] ||= @group
68
68
 
69
- _normalize_git_options(name, version, opts)
70
- end
71
-
72
- def _normalize_git_options(name, version, opts)
73
- # Normalize Git options
74
- if opts["git"]
75
- source = git(opts["git"], :ref => opts["ref"])
76
- source.default_spec name, version if _version?(version)
77
- opts["source"] = source
69
+ # Normalize git and path options
70
+ ["git", "path"].each do |type|
71
+ if param = opts[type]
72
+ source = send(type, param, opts.merge(:prepend => true))
73
+ source.default_spec name, version if _version?(version)
74
+ opts["source"] = source
75
+ end
78
76
  end
79
77
  end
80
-
81
78
  end
82
79
  end
@@ -24,9 +24,15 @@ module Bundler
24
24
  end
25
25
 
26
26
  def lock
27
+ Bundler.ui.info("The bundle is already locked, relocking.")
27
28
  FileUtils.mkdir_p("#{root}/vendor")
28
29
  write_yml_lock
29
30
  write_rb_lock
31
+ Bundler.ui.info("The bundle is locked. Use `bundle show` to list the gems in the environment.")
32
+ end
33
+
34
+ def locked?
35
+ File.exist?("#{root}/Gemfile.lock")
30
36
  end
31
37
 
32
38
  def specs_for(*groups)
@@ -48,6 +54,8 @@ module Bundler
48
54
  end
49
55
  end
50
56
 
57
+ alias gems specs
58
+
51
59
  def index
52
60
  @definition.local_index
53
61
  end
@@ -56,10 +64,12 @@ module Bundler
56
64
  pack_path = "#{root}/vendor/cache/"
57
65
  FileUtils.mkdir_p(pack_path)
58
66
 
67
+ Bundler.ui.info "Copying .gem files into vendor/cache"
59
68
  specs.each do |spec|
60
- next if spec.source && !spec.source.is_a?(Source::Rubygems)
69
+ next unless spec.source.is_a?(Source::SystemGems) || spec.source.is_a?(Source::Rubygems)
61
70
  possibilities = Gem.path.map { |p| "#{p}/cache/#{spec.full_name}.gem" }
62
71
  cached_path = possibilities.find { |p| File.exist? p }
72
+ Bundler.ui.info " * #{File.basename(cached_path)}"
63
73
  FileUtils.cp(cached_path, pack_path)
64
74
  end
65
75
  end
@@ -110,7 +120,7 @@ module Bundler
110
120
 
111
121
  def write_yml_lock
112
122
  yml = details.to_yaml
113
- File.open("#{root}/vendor/lock.yml", 'w') do |f|
123
+ File.open("#{root}/Gemfile.lock", 'w') do |f|
114
124
  f.puts yml
115
125
  end
116
126
  end
@@ -1,14 +1,7 @@
1
1
  module Bundler
2
2
  class Index
3
3
  def self.from_installed_gems
4
- # TODO: Why can't we memoize this? It is being mutated somewhere
5
- from_gem_index(Gem::SourceIndex.from_installed_gems)
6
- end
7
-
8
- def self.from_gem_index(gem_index)
9
- index = new
10
- gem_index.each { |name, spec| index << spec }
11
- index
4
+ Source::SystemGems.new.specs
12
5
  end
13
6
 
14
7
  def initialize
@@ -19,9 +19,12 @@ module Bundler
19
19
  return
20
20
  end
21
21
 
22
- specs.each do |spec|
23
- next unless spec.source.respond_to?(:install)
24
- next if (spec.groups & options[:without]).any?
22
+ specs.sort_by { |s| s.name }.each do |spec|
23
+ Bundler.ui.info "* #{spec.name} (#{spec.version})"
24
+ if (spec.groups & options[:without]).any?
25
+ Bundler.ui.info " * Not in requested group... skipping."
26
+ next
27
+ end
25
28
  spec.source.install(spec)
26
29
  end
27
30
 
@@ -19,12 +19,6 @@ module Bundler
19
19
  end
20
20
 
21
21
  def install(spec)
22
- Bundler.ui.info "* #{spec.name} (#{spec.version})"
23
- if Index.from_installed_gems[spec].any?
24
- Bundler.ui.info " * already installed... skipping"
25
- return
26
- end
27
-
28
22
  destination = Gem.dir
29
23
 
30
24
  Bundler.ui.info " * Downloading..."
@@ -66,6 +60,29 @@ module Bundler
66
60
  end
67
61
  end
68
62
 
63
+ class SystemGems
64
+ def specs
65
+ @specs ||= begin
66
+ index = Index.new
67
+
68
+ Gem::SourceIndex.from_installed_gems.each do |name, spec|
69
+ spec.source = self
70
+ index << spec
71
+ end
72
+
73
+ index
74
+ end
75
+ end
76
+
77
+ def to_s
78
+ "System gem source"
79
+ end
80
+
81
+ def install(spec)
82
+ Bundler.ui.info " * already installed... skipping"
83
+ end
84
+ end
85
+
69
86
  class GemCache
70
87
  def initialize(options)
71
88
  @path = options[:path]
@@ -88,6 +105,7 @@ module Bundler
88
105
  def install(spec)
89
106
  destination = Gem.dir
90
107
 
108
+ Bundler.ui.info " * Installing from pack..."
91
109
  installer = Gem::Installer.new "#{@path}/#{spec.full_name}.gem",
92
110
  :install_dir => Gem.dir,
93
111
  :ignore_dependencies => true
@@ -124,7 +142,9 @@ module Bundler
124
142
  if File.directory?(path)
125
143
  Dir["#{path}/#{@glob}"].each do |file|
126
144
  file = Pathname.new(file)
127
- if spec = eval(File.read(file))
145
+ # Do it in the root of the repo in case they do
146
+ # assume being in the root
147
+ if spec = Dir.chdir(path) { eval(File.read(file)) }
128
148
  spec = Specification.from_gemspec(spec)
129
149
  spec.loaded_from = file
130
150
  spec.source = self
@@ -139,6 +159,10 @@ module Bundler
139
159
  end
140
160
  end
141
161
 
162
+ def install(spec)
163
+ Bundler.ui.info " * Using path `#{path}`..."
164
+ end
165
+
142
166
  alias specs local_specs
143
167
 
144
168
  end
@@ -196,7 +220,12 @@ module Bundler
196
220
  end
197
221
 
198
222
  def install(spec)
199
- @installed ||= begin
223
+ Bundler.ui.info " * Using git `#{uri}`..."
224
+
225
+ if @installed
226
+ Bundler.ui.info " * Already checked out revision: #{ref}..."
227
+ else
228
+ Bundler.ui.info " * Checking out revision: #{ref}..."
200
229
  FileUtils.mkdir_p(path)
201
230
  Dir.chdir(path) do
202
231
  unless File.exist?(".git")
@@ -207,7 +236,7 @@ module Bundler
207
236
  %x(git submodule init)
208
237
  %x(git submodule update)
209
238
  end
210
- true
239
+ @installed = true
211
240
  end
212
241
  end
213
242
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0.pre3
4
+ version: 0.9.0.pre4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carl Lerche
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2010-01-31 00:00:00 -08:00
13
+ date: 2010-02-02 00:00:00 -08:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -70,7 +70,7 @@ files:
70
70
  - lib/bundler/vendor/thor.rb
71
71
  - lib/bundler.rb
72
72
  - LICENSE
73
- - README
73
+ - README.markdown
74
74
  has_rdoc: true
75
75
  homepage: http://github.com/carlhuda/bundler
76
76
  licenses: []
data/README DELETED
@@ -1,7 +0,0 @@
1
- This is a rewrite of bundler to offer more bundling power
2
-
3
- It currently lacks output and good exception handling for common cases. This is coming very soon. We wanted to open this so people could take a look at it.
4
-
5
- More soon.
6
-
7
- - carlhuda