bundler 0.3.0
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/LICENSE +20 -0
- data/README.markdown +156 -0
- data/Rakefile +46 -0
- data/lib/bundler.rb +34 -0
- data/lib/bundler/cli.rb +43 -0
- data/lib/bundler/commands/bundle_command.rb +29 -0
- data/lib/bundler/commands/exec_command.rb +29 -0
- data/lib/bundler/dependency.rb +45 -0
- data/lib/bundler/finder.rb +89 -0
- data/lib/bundler/gem_bundle.rb +16 -0
- data/lib/bundler/gem_ext.rb +19 -0
- data/lib/bundler/manifest.rb +136 -0
- data/lib/bundler/manifest_file.rb +75 -0
- data/lib/bundler/repository.rb +87 -0
- data/lib/bundler/resolver.rb +77 -0
- data/lib/bundler/runtime.rb +59 -0
- data/lib/bundler/templates/app_script.rb +3 -0
- data/lib/bundler/templates/environment.rb +82 -0
- data/lib/bundler/templates/rubygems.rb +5 -0
- data/lib/rubygems_plugin.rb +7 -0
- metadata +75 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Engine Yard
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,156 @@
|
|
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
|
+
|
6
|
+
## Intro
|
7
|
+
|
8
|
+
Bundler is a tool that manages gem dependencies for your ruby application. It
|
9
|
+
takes a gem manifest file and is able to fetch, download, and install the gems
|
10
|
+
and all child dependencies specified in this manifest. It can manage any update
|
11
|
+
to the gem manifest file and update the bundled gems accordingly. It also lets
|
12
|
+
you run any ruby code in context of the bundled gem environment.
|
13
|
+
|
14
|
+
## Disclaimer
|
15
|
+
|
16
|
+
This project is under rapid development. It is usable today, but there will be
|
17
|
+
many changes in the near future, including to the Gemfile DSL. We will bump up
|
18
|
+
versions with changes though. We greatly appreciate feedback.
|
19
|
+
|
20
|
+
## Installation
|
21
|
+
|
22
|
+
Bundler has no dependencies. Just clone the git repository and install the gem
|
23
|
+
with the following rake task:
|
24
|
+
|
25
|
+
rake install
|
26
|
+
|
27
|
+
## Usage
|
28
|
+
|
29
|
+
Bundler requires a gem manifest file to be created. This should be a file named
|
30
|
+
`Gemfile` located in the root directory of your application. After the manifest
|
31
|
+
has been created, in your shell, cd into your application's directory and run
|
32
|
+
`gem bundle`. This will start the bundling process.
|
33
|
+
|
34
|
+
### Manifest file
|
35
|
+
|
36
|
+
This is where you specify all of your application's dependencies. By default
|
37
|
+
this should be in a file named `Gemfile` located in your application's root
|
38
|
+
directory. The following is an example of a potential `Gemfile`. For more
|
39
|
+
information, please refer to Bundler::ManifestBuilder.
|
40
|
+
|
41
|
+
# Specify a dependency on rails. When the bundler downloads gems,
|
42
|
+
# it will download rails as well as all of rails' dependencies (such as
|
43
|
+
# activerecord, actionpack, etc...)
|
44
|
+
#
|
45
|
+
# At least one dependency must be specified
|
46
|
+
gem "rails"
|
47
|
+
|
48
|
+
# Specify a dependency on rack v.1.0.0. The version is optional. If present,
|
49
|
+
# it can be specified the same way as with rubygems' #gem method.
|
50
|
+
gem "rack", "1.0.0"
|
51
|
+
|
52
|
+
# Specify a dependency rspec, but only activate that gem in the "testing"
|
53
|
+
# environment (read more about environments later). :except is also a valid
|
54
|
+
# option to specify environment restrictions.
|
55
|
+
gem "rspec", :only => :testing
|
56
|
+
|
57
|
+
# Add http://gems.github.com as a source that the bundler will use
|
58
|
+
# to find gems listed in the manifest. By default,
|
59
|
+
# http://gems.rubyforge.org is already added to the list.
|
60
|
+
#
|
61
|
+
# This is an optional setting.
|
62
|
+
source "http://gems.github.com"
|
63
|
+
|
64
|
+
# Specify where the bundled gems should be stashed. This directory will
|
65
|
+
# be a gem repository where all gems are downloaded to and installed to.
|
66
|
+
#
|
67
|
+
# This is an optional setting.
|
68
|
+
# The default is: vendor/gems
|
69
|
+
bundle_path "my/bundled/gems"
|
70
|
+
|
71
|
+
# Specify where gem executables should be copied to.
|
72
|
+
#
|
73
|
+
# This is an optional setting.
|
74
|
+
# The default is: bin
|
75
|
+
bin_path "my/executables"
|
76
|
+
|
77
|
+
# Specify that rubygems should be completely disabled. This means that it
|
78
|
+
# will be impossible to require it and that available gems will be
|
79
|
+
# limited exclusively to gems that have been bundled.
|
80
|
+
#
|
81
|
+
# The default is to automatically require rubygems. There is also a
|
82
|
+
# `disable_system_gems` option that will limit available rubygems to
|
83
|
+
# the ones that have been bundled.
|
84
|
+
disable_rubygems
|
85
|
+
|
86
|
+
### Running Bundler
|
87
|
+
|
88
|
+
Once a manifest file has been created, the only thing that needs to be done
|
89
|
+
is to run the `gem bundle` command anywhere in your application. The script
|
90
|
+
will load the manifest file, resole all the dependencies, download all
|
91
|
+
needed gems, and install them into the specified directory.
|
92
|
+
|
93
|
+
Every time an update is made to the manifest file, run `gem bundle` again to
|
94
|
+
get the changes installed. This will only check the remote sources if your
|
95
|
+
currently installed gems do not satisfy the `Gemfile`. If you want to force
|
96
|
+
checking for updates on the remote sources, use the `--update` option.
|
97
|
+
|
98
|
+
### Running your application
|
99
|
+
|
100
|
+
The easiest way to run your application is to start it with an executable
|
101
|
+
copied to the specified bin directory (by default, simply bin). For example,
|
102
|
+
if the application in question is a rack app, start it with `bin/rackup`.
|
103
|
+
This will automatically set the gem environment correctly.
|
104
|
+
|
105
|
+
Another way to run arbitrary ruby code in context of the bundled gems is to
|
106
|
+
run it with the `gem exec` command. For example:
|
107
|
+
|
108
|
+
gem exec ruby my_ruby_script.rb
|
109
|
+
|
110
|
+
Yet another way is to manually require the environment file first. This is
|
111
|
+
located in `[bundle_path]/environments/default.rb`. For example:
|
112
|
+
|
113
|
+
ruby -r vendor/gems/environments/default.rb my_ruby_script.rb
|
114
|
+
|
115
|
+
### Using Bundler with Rails today
|
116
|
+
|
117
|
+
It should be possible to use Bundler with Rails today. Here are the steps
|
118
|
+
to follow.
|
119
|
+
|
120
|
+
* In your rails app, create a Gemfile and specify the gems that your
|
121
|
+
application depends on. Make sure to specify rails as well:
|
122
|
+
|
123
|
+
gem "rails", "2.1.2"
|
124
|
+
gem "will_paginate"
|
125
|
+
|
126
|
+
# Optionally, you can disable system gems all together and only
|
127
|
+
# use bundled gems.
|
128
|
+
disable_system_gems
|
129
|
+
|
130
|
+
* Run `gem bundle`
|
131
|
+
|
132
|
+
* You can now use rails if you prepend `gem exec` to every call to `script/*`
|
133
|
+
but that isn't fun.
|
134
|
+
|
135
|
+
* At the top of `config/boot.rb`, add the following line:
|
136
|
+
|
137
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'vendor', 'gems', 'environments', 'default'))
|
138
|
+
|
139
|
+
In theory, this should be enough to get going.
|
140
|
+
|
141
|
+
## To require rubygems or not
|
142
|
+
|
143
|
+
Ideally, no gem would assume the presence of rubygems at runtime. Rubygems provides
|
144
|
+
enough features so that this isn't necessary. However, there are a number of gems
|
145
|
+
that require specific rubygem features.
|
146
|
+
|
147
|
+
If the `disable_rubygems` option is used, Bundler will stub out the most common
|
148
|
+
of these features, but it is possible that things will not go as intended quite
|
149
|
+
yet. So, if you are brave, try your code without rubygems at runtime.
|
150
|
+
|
151
|
+
## Reporting bugs
|
152
|
+
|
153
|
+
Please report all bugs on the github issue tracker for the project located
|
154
|
+
at:
|
155
|
+
|
156
|
+
http://github.com/wycats/bundler/issues/
|
data/Rakefile
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'rubygems/specification'
|
4
|
+
require 'date'
|
5
|
+
require 'spec/rake/spectask'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
s.name = "bundler"
|
9
|
+
s.version = "0.3.0"
|
10
|
+
s.author = "Yehuda Katz"
|
11
|
+
s.email = "wycats@gmail.com"
|
12
|
+
s.homepage = "http://github.com/wycats/bundler"
|
13
|
+
s.description = s.summary = "An easy way to vendor gem dependencies"
|
14
|
+
|
15
|
+
s.platform = Gem::Platform::RUBY
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.extra_rdoc_files = ["README.markdown", "LICENSE"]
|
18
|
+
|
19
|
+
s.require_path = 'lib'
|
20
|
+
s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("lib/**/*")
|
21
|
+
end
|
22
|
+
|
23
|
+
task :default => :spec
|
24
|
+
|
25
|
+
desc "Run specs"
|
26
|
+
Spec::Rake::SpecTask.new do |t|
|
27
|
+
t.spec_files = FileList['spec/**/*_spec.rb'] - FileList['spec/fixtures/**/*_spec.rb']
|
28
|
+
t.spec_opts = %w(-fs --color)
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
33
|
+
pkg.gem_spec = spec
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "install the gem locally"
|
37
|
+
task :install => [:package] do
|
38
|
+
sh %{gem install pkg/#{spec.name}-#{spec.version}}
|
39
|
+
end
|
40
|
+
|
41
|
+
desc "create a gemspec file"
|
42
|
+
task :make_spec do
|
43
|
+
File.open("#{spec.name}.gemspec", "w") do |file|
|
44
|
+
file.puts spec.to_ruby
|
45
|
+
end
|
46
|
+
end
|
data/lib/bundler.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'logger'
|
3
|
+
require 'set'
|
4
|
+
require 'erb'
|
5
|
+
# Required elements of rubygems
|
6
|
+
require "rubygems/remote_fetcher"
|
7
|
+
require "rubygems/installer"
|
8
|
+
|
9
|
+
require "bundler/gem_bundle"
|
10
|
+
require "bundler/finder"
|
11
|
+
require "bundler/gem_ext"
|
12
|
+
require "bundler/resolver"
|
13
|
+
require "bundler/manifest_file"
|
14
|
+
require "bundler/manifest"
|
15
|
+
require "bundler/dependency"
|
16
|
+
require "bundler/runtime"
|
17
|
+
require "bundler/cli"
|
18
|
+
require "bundler/repository"
|
19
|
+
|
20
|
+
module Bundler
|
21
|
+
VERSION = "0.5.0"
|
22
|
+
|
23
|
+
class << self
|
24
|
+
attr_writer :logger
|
25
|
+
|
26
|
+
def logger
|
27
|
+
@logger ||= begin
|
28
|
+
logger = Logger.new(STDOUT, Logger::INFO)
|
29
|
+
logger.formatter = proc {|_,_,_,msg| "#{msg}\n" }
|
30
|
+
logger
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/bundler/cli.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
require "optparse"
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
class CLI
|
5
|
+
def self.run(command, options = {})
|
6
|
+
new(options).run(command)
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize(options)
|
10
|
+
@options = options
|
11
|
+
@manifest_file = Bundler::ManifestFile.load(@options[:manifest])
|
12
|
+
end
|
13
|
+
|
14
|
+
def bundle
|
15
|
+
@manifest_file.install(@options[:update])
|
16
|
+
end
|
17
|
+
|
18
|
+
def exec
|
19
|
+
@manifest_file.setup_environment
|
20
|
+
# w0t?
|
21
|
+
super(*@options[:args])
|
22
|
+
end
|
23
|
+
|
24
|
+
def run(command)
|
25
|
+
|
26
|
+
send(command)
|
27
|
+
|
28
|
+
rescue DefaultManifestNotFound => e
|
29
|
+
Bundler.logger.error "Could not find a Gemfile to use"
|
30
|
+
exit 2
|
31
|
+
rescue InvalidEnvironmentName => e
|
32
|
+
Bundler.logger.error "Gemfile error: #{e.message}"
|
33
|
+
exit
|
34
|
+
rescue InvalidRepository => e
|
35
|
+
Bundler.logger.error e.message
|
36
|
+
exit
|
37
|
+
rescue VersionConflict => e
|
38
|
+
Bundler.logger.error e.message
|
39
|
+
exit
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Gem::Commands::BundleCommand < Gem::Command
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
super('bundle', 'Create a gem bundle based on your Gemfile', {:manifest => nil, :update => false})
|
5
|
+
|
6
|
+
add_option('-m', '--manifest MANIFEST', "Specify the path to the manifest file") do |manifest, options|
|
7
|
+
options[:manifest] = Pathname.new(manifest)
|
8
|
+
end
|
9
|
+
|
10
|
+
add_option('-u', '--update', "Force a remote check for newer gems") do
|
11
|
+
options[:update] = true
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def usage
|
16
|
+
"#{program_name}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def description # :nodoc:
|
20
|
+
<<-EOF
|
21
|
+
Bundle stuff
|
22
|
+
EOF
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute
|
26
|
+
Bundler::CLI.run(:bundle, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class Gem::Commands::ExecCommand < Gem::Command
|
2
|
+
|
3
|
+
def initialize
|
4
|
+
super('exec', 'Run a command in context of a gem bundle', {:manifest => nil})
|
5
|
+
|
6
|
+
add_option('-m', '--manifest MANIFEST', "Specify the path to the manifest file") do |manifest, options|
|
7
|
+
options[:manifest] = Pathname.new(manifest)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def usage
|
12
|
+
"#{program_name} COMMAND"
|
13
|
+
end
|
14
|
+
|
15
|
+
def arguments # :nodoc:
|
16
|
+
"COMMAND command to run in context of the gem bundle"
|
17
|
+
end
|
18
|
+
|
19
|
+
def description # :nodoc:
|
20
|
+
<<-EOF.gsub(' ', '')
|
21
|
+
Run in context of a bundle
|
22
|
+
EOF
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute
|
26
|
+
Bundler::CLI.run(:exec, options)
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Bundler
|
2
|
+
class InvalidEnvironmentName < StandardError; end
|
3
|
+
|
4
|
+
class Dependency
|
5
|
+
attr_reader :name, :version, :require_as, :only, :except
|
6
|
+
|
7
|
+
def initialize(name, options = {})
|
8
|
+
options.each do |k, v|
|
9
|
+
options[k.to_s] = v
|
10
|
+
end
|
11
|
+
|
12
|
+
@name = name
|
13
|
+
@version = options["version"] || ">= 0"
|
14
|
+
@require_as = Array(options["require_as"] || name)
|
15
|
+
@only = Array(options["only"]).map {|e| e.to_s } if options["only"]
|
16
|
+
@except = Array(options["except"]).map {|e| e.to_s } if options["except"]
|
17
|
+
|
18
|
+
if (@only && @only.include?("rubygems")) || (@except && @except.include?("rubygems"))
|
19
|
+
raise InvalidEnvironmentName, "'rubygems' is not a valid environment name"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def in?(environment)
|
24
|
+
environment = environment.to_s
|
25
|
+
|
26
|
+
return false unless !@only || @only.include?(environment)
|
27
|
+
return false if @except && @except.include?(environment)
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
to_gem_dependency.to_s
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_gem_dependency
|
36
|
+
@gem_dep ||= Gem::Dependency.new(name, version)
|
37
|
+
end
|
38
|
+
|
39
|
+
def ==(o)
|
40
|
+
[name, version, require_as, only, except] ==
|
41
|
+
[o.name, o.version, o.require_as, o.only, o.except]
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Bundler
|
2
|
+
# Finder behaves like a rubygems source index in that it responds
|
3
|
+
# to #search. It also resolves a list of dependencies finding the
|
4
|
+
# best possible configuration of gems that satisifes all requirements
|
5
|
+
# without causing any gem activation errors.
|
6
|
+
class Finder
|
7
|
+
|
8
|
+
# Takes an array of gem sources and fetches the full index of
|
9
|
+
# gems from each one. It then combines the indexes together keeping
|
10
|
+
# track of the original source so that any resolved gem can be
|
11
|
+
# fetched from the correct source.
|
12
|
+
#
|
13
|
+
# ==== Parameters
|
14
|
+
# *sources<String>:: URI pointing to the gem repository
|
15
|
+
def initialize(*sources)
|
16
|
+
@results = {}
|
17
|
+
@index = Hash.new { |h,k| h[k] = {} }
|
18
|
+
|
19
|
+
sources.each { |source| fetch(source) }
|
20
|
+
end
|
21
|
+
|
22
|
+
# Figures out the best possible configuration of gems that satisfies
|
23
|
+
# the list of passed dependencies and any child dependencies without
|
24
|
+
# causing any gem activation errors.
|
25
|
+
#
|
26
|
+
# ==== Parameters
|
27
|
+
# *dependencies<Gem::Dependency>:: The list of dependencies to resolve
|
28
|
+
#
|
29
|
+
# ==== Returns
|
30
|
+
# <GemBundle>,nil:: If the list of dependencies can be resolved, a
|
31
|
+
# collection of gemspecs is returned. Otherwise, nil is returned.
|
32
|
+
def resolve(*dependencies)
|
33
|
+
Bundler.logger.info "Calculating dependencies..."
|
34
|
+
|
35
|
+
resolved = Resolver.resolve(dependencies, self)
|
36
|
+
resolved && GemBundle.new(resolved)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Fetches the index from the remote source
|
40
|
+
#
|
41
|
+
# ==== Parameters
|
42
|
+
# source<String>:: URI pointing to the gem repository
|
43
|
+
#
|
44
|
+
# ==== Raises
|
45
|
+
# ArgumentError:: If the source is not a valid gem repository
|
46
|
+
def fetch(source)
|
47
|
+
Bundler.logger.info "Updating source: #{source}"
|
48
|
+
|
49
|
+
deflated = Gem::RemoteFetcher.fetcher.fetch_path("#{source}/Marshal.4.8.Z")
|
50
|
+
inflated = Gem.inflate deflated
|
51
|
+
|
52
|
+
append(Marshal.load(inflated), source)
|
53
|
+
rescue Gem::RemoteFetcher::FetchError => e
|
54
|
+
raise ArgumentError, "#{source} is not a valid source: #{e.message}"
|
55
|
+
end
|
56
|
+
|
57
|
+
# Adds a new gem index linked to a gem source to the over all
|
58
|
+
# gem index that gets searched.
|
59
|
+
#
|
60
|
+
# ==== Parameters
|
61
|
+
# index<Gem::SourceIndex>:: The index to append to the list
|
62
|
+
# source<String>:: The original source
|
63
|
+
def append(index, source)
|
64
|
+
index.gems.values.each do |spec|
|
65
|
+
next unless Gem::Platform.match(spec.platform)
|
66
|
+
spec.source = source
|
67
|
+
@index[spec.name][spec.version] ||= spec
|
68
|
+
end
|
69
|
+
self
|
70
|
+
end
|
71
|
+
|
72
|
+
# Searches for a gem that matches the dependency
|
73
|
+
#
|
74
|
+
# ==== Parameters
|
75
|
+
# dependency<Gem::Dependency>:: The gem dependency to search for
|
76
|
+
#
|
77
|
+
# ==== Returns
|
78
|
+
# [Gem::Specification]:: A collection of gem specifications
|
79
|
+
# matching the search
|
80
|
+
def search(dependency)
|
81
|
+
@results[dependency.hash] ||= begin
|
82
|
+
possibilities = @index[dependency.name].values
|
83
|
+
possibilities.select do |spec|
|
84
|
+
dependency =~ spec
|
85
|
+
end.sort_by {|s| s.version }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Bundler
|
2
|
+
class GemBundle < Array
|
3
|
+
def download(directory)
|
4
|
+
FileUtils.mkdir_p(directory)
|
5
|
+
|
6
|
+
each do |spec|
|
7
|
+
unless directory.join("cache", "#{spec.full_name}.gem").file?
|
8
|
+
Bundler.logger.info "Downloading #{spec.full_name}.gem"
|
9
|
+
Gem::RemoteFetcher.fetcher.download(spec, spec.source, directory)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
self
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Gem
|
2
|
+
class Installer
|
3
|
+
def app_script_text(bin_file_name)
|
4
|
+
path = @gem_home
|
5
|
+
template = File.read(File.join(File.dirname(__FILE__), "templates", "app_script.rb"))
|
6
|
+
erb = ERB.new(template)
|
7
|
+
erb.result(binding)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class Specification
|
12
|
+
attribute :source
|
13
|
+
|
14
|
+
def source=(source)
|
15
|
+
@source = source.is_a?(URI) ? source : URI.parse(source)
|
16
|
+
raise ArgumentError, "The source must be an absolute URI" unless @source.absolute?
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require "rubygems/source_index"
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
class VersionConflict < StandardError; end
|
5
|
+
|
6
|
+
class Manifest
|
7
|
+
attr_reader :sources, :dependencies, :path
|
8
|
+
|
9
|
+
def initialize(sources, dependencies, bindir, repository_path, rubygems, system_gems)
|
10
|
+
sources.map! {|s| s.is_a?(URI) ? s : URI.parse(s) }
|
11
|
+
@sources = sources
|
12
|
+
@dependencies = dependencies
|
13
|
+
@bindir = bindir
|
14
|
+
@repository = Repository.new(repository_path)
|
15
|
+
@rubygems = rubygems
|
16
|
+
@system_gems = system_gems
|
17
|
+
end
|
18
|
+
|
19
|
+
def install(update)
|
20
|
+
fetch(update)
|
21
|
+
@repository.install_cached_gems(:bin_dir => @bindir || @repository.path.join("bin"))
|
22
|
+
cleanup_removed_gems
|
23
|
+
create_environment_files(@repository.path.join("environments"))
|
24
|
+
Bundler.logger.info "Done."
|
25
|
+
end
|
26
|
+
|
27
|
+
def activate(environment = "default")
|
28
|
+
require @repository.path.join("environments", "#{environment}.rb")
|
29
|
+
end
|
30
|
+
|
31
|
+
def require_all
|
32
|
+
dependencies.each do |dep|
|
33
|
+
dep.require_as.each {|file| require file }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def gems_for(environment = nil)
|
38
|
+
deps = dependencies
|
39
|
+
deps = deps.select { |d| d.in?(environment) } if environment
|
40
|
+
deps = deps.map { |d| d.to_gem_dependency }
|
41
|
+
Resolver.resolve(deps, @repository.source_index)
|
42
|
+
end
|
43
|
+
alias gems gems_for
|
44
|
+
|
45
|
+
def environments
|
46
|
+
envs = dependencies.map {|dep| Array(dep.only) + Array(dep.except) }.flatten
|
47
|
+
envs << "default"
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def fetch(update)
|
53
|
+
return unless update || !all_gems_installed?
|
54
|
+
|
55
|
+
finder = Finder.new(*sources)
|
56
|
+
unless bundle = finder.resolve(*gem_dependencies)
|
57
|
+
gems = @dependencies.map {|d| " #{d.to_s}" }.join("\n")
|
58
|
+
raise VersionConflict, "No compatible versions could be found for:\n#{gems}"
|
59
|
+
end
|
60
|
+
|
61
|
+
bundle.download(@repository.path)
|
62
|
+
end
|
63
|
+
|
64
|
+
def gem_dependencies
|
65
|
+
@gem_dependencies ||= dependencies.map { |d| d.to_gem_dependency }
|
66
|
+
end
|
67
|
+
|
68
|
+
def all_gems_installed?
|
69
|
+
downloaded_gems = {}
|
70
|
+
|
71
|
+
Dir[@repository.path.join("cache", "*.gem")].each do |file|
|
72
|
+
file =~ /\/([^\/]+)-([\d\.]+)\.gem$/
|
73
|
+
name, version = $1, $2
|
74
|
+
downloaded_gems[name] = Gem::Version.new(version)
|
75
|
+
end
|
76
|
+
|
77
|
+
gem_dependencies.all? do |dep|
|
78
|
+
downloaded_gems[dep.name] &&
|
79
|
+
dep.version_requirements.satisfied_by?(downloaded_gems[dep.name])
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def cleanup_removed_gems
|
84
|
+
glob = gems.map { |g| g.full_name }.join(',')
|
85
|
+
base = @repository.path.join("{cache,specifications,gems}")
|
86
|
+
|
87
|
+
(Dir[base.join("*")] - Dir[base.join("{#{glob}}{.gemspec,.gem,}")]).each do |file|
|
88
|
+
Bundler.logger.info "Deleting gem: #{File.basename(file, ".gem")}" if File.basename(file) =~ /\.gem$/
|
89
|
+
FileUtils.rm_rf(file)
|
90
|
+
end
|
91
|
+
|
92
|
+
glob = gems.map { |g| g.executables }.flatten.join(',')
|
93
|
+
(Dir[@bindir.join("*")] - Dir[@bindir.join("{#{glob}}")]).each do |file|
|
94
|
+
Bundler.logger.info "Deleting bin file: #{File.basename(file)}"
|
95
|
+
FileUtils.rm_rf(file)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def create_environment_files(path)
|
100
|
+
FileUtils.mkdir_p(path)
|
101
|
+
environments.each do |environment|
|
102
|
+
specs = gems_for(environment)
|
103
|
+
files = spec_files_for_specs(specs, path)
|
104
|
+
load_paths = load_paths_for_specs(specs)
|
105
|
+
create_environment_file(path, environment, files, load_paths)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def create_environment_file(path, environment, spec_files, load_paths)
|
110
|
+
File.open(path.join("#{environment}.rb"), "w") do |file|
|
111
|
+
template = File.read(File.join(File.dirname(__FILE__), "templates", "environment.rb"))
|
112
|
+
erb = ERB.new(template)
|
113
|
+
file.puts erb.result(binding)
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
def load_paths_for_specs(specs)
|
118
|
+
load_paths = []
|
119
|
+
specs.each do |spec|
|
120
|
+
load_paths << File.join(spec.full_gem_path, spec.bindir) if spec.bindir
|
121
|
+
spec.require_paths.each do |path|
|
122
|
+
load_paths << File.join(spec.full_gem_path, path)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
load_paths
|
126
|
+
end
|
127
|
+
|
128
|
+
def spec_files_for_specs(specs, path)
|
129
|
+
files = {}
|
130
|
+
specs.each do |s|
|
131
|
+
files[s.name] = path.join("..", "specifications", "#{s.full_name}.gemspec").expand_path
|
132
|
+
end
|
133
|
+
files
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Bundler
|
2
|
+
class DefaultManifestNotFound < StandardError; end
|
3
|
+
|
4
|
+
class ManifestFile
|
5
|
+
attr_reader :sources, :dependencies
|
6
|
+
attr_accessor :gem_path, :bindir, :rubygems, :system_gems
|
7
|
+
|
8
|
+
def self.load(filename = nil)
|
9
|
+
new(filename).load
|
10
|
+
end
|
11
|
+
|
12
|
+
def initialize(filename)
|
13
|
+
@filename = filename
|
14
|
+
@sources = %w(http://gems.rubyforge.org)
|
15
|
+
@dependencies = []
|
16
|
+
@rubygems = true
|
17
|
+
@system_gems = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def load
|
21
|
+
manifest
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def manifest
|
26
|
+
@manifest ||= load_manifest
|
27
|
+
end
|
28
|
+
|
29
|
+
def install(update = false)
|
30
|
+
manifest.install(update)
|
31
|
+
end
|
32
|
+
|
33
|
+
def setup_environment
|
34
|
+
unless @system_gems
|
35
|
+
ENV["GEM_HOME"] = @gem_path
|
36
|
+
ENV["GEM_PATH"] = @gem_path
|
37
|
+
end
|
38
|
+
ENV["PATH"] = "#{@bindir}:#{ENV["PATH"]}"
|
39
|
+
ENV["RUBYOPT"] = "-r#{@gem_path}/environments/default #{ENV["RUBYOPT"]}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def load_manifest
|
43
|
+
ManifestBuilder.load(self, filename)
|
44
|
+
Manifest.new(sources, dependencies, bindir, gem_path, rubygems, system_gems)
|
45
|
+
end
|
46
|
+
|
47
|
+
def gem_path
|
48
|
+
@gem_path ||= root.join("vendor", "gems")
|
49
|
+
end
|
50
|
+
|
51
|
+
def bindir
|
52
|
+
@bindir ||= root.join("bin")
|
53
|
+
end
|
54
|
+
|
55
|
+
def root
|
56
|
+
filename.parent
|
57
|
+
end
|
58
|
+
|
59
|
+
def filename
|
60
|
+
@filename ||= find_manifest_file
|
61
|
+
end
|
62
|
+
|
63
|
+
def find_manifest_file
|
64
|
+
current = Pathname.new(Dir.pwd)
|
65
|
+
|
66
|
+
until current.root?
|
67
|
+
filename = current.join("Gemfile")
|
68
|
+
return filename if filename.exist?
|
69
|
+
current = current.parent
|
70
|
+
end
|
71
|
+
|
72
|
+
raise DefaultManifestNotFound
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Bundler
|
2
|
+
class InvalidRepository < StandardError ; end
|
3
|
+
|
4
|
+
class Repository
|
5
|
+
|
6
|
+
attr_reader :path
|
7
|
+
|
8
|
+
def initialize(path)
|
9
|
+
@path = Pathname.new(path)
|
10
|
+
unless valid?
|
11
|
+
raise InvalidRepository, "'#{path}' is not a valid gem repository"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the source index for all gems installed in the
|
16
|
+
# repository
|
17
|
+
def source_index
|
18
|
+
Gem::SourceIndex.from_gems_in(@path.join("specifications"))
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid?
|
22
|
+
(Dir[@path.join("*")] - Dir[@path.join("{cache,doc,gems,environments,specifications}")]).empty?
|
23
|
+
end
|
24
|
+
|
25
|
+
# Checks whether a gem is installed
|
26
|
+
def install_cached_gems(options = {})
|
27
|
+
cached_gems.each do |name, version|
|
28
|
+
unless installed?(name, version)
|
29
|
+
install_cached_gem(name, version, options)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def install_cached_gem(name, version, options = {})
|
35
|
+
cached_gem = cache_path.join("#{name}-#{version}.gem")
|
36
|
+
if cached_gem.file?
|
37
|
+
Bundler.logger.info "Installing #{name}-#{version}.gem"
|
38
|
+
installer = Gem::Installer.new(cached_gem.to_s, options.merge(
|
39
|
+
:install_dir => @path,
|
40
|
+
:ignore_dependencies => true,
|
41
|
+
:env_shebang => true,
|
42
|
+
:wrappers => true
|
43
|
+
))
|
44
|
+
installer.install
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def cache_path
|
51
|
+
@path.join("cache")
|
52
|
+
end
|
53
|
+
|
54
|
+
def cache_files
|
55
|
+
Dir[cache_path.join("*.gem")]
|
56
|
+
end
|
57
|
+
|
58
|
+
def cached_gems
|
59
|
+
cache_files.map do |f|
|
60
|
+
full_name = File.basename(f).gsub(/\.gem$/, '')
|
61
|
+
full_name.split(/-(?=[\d.]+$)/)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def spec_path
|
66
|
+
@path.join("specifications")
|
67
|
+
end
|
68
|
+
|
69
|
+
def spec_files
|
70
|
+
Dir[spec_path.join("*.gemspec")]
|
71
|
+
end
|
72
|
+
|
73
|
+
def gem_path
|
74
|
+
@path.join("gems")
|
75
|
+
end
|
76
|
+
|
77
|
+
def gems
|
78
|
+
Dir[gem_path.join("*")]
|
79
|
+
end
|
80
|
+
|
81
|
+
def installed?(name, version)
|
82
|
+
spec_files.any? { |g| File.basename(g) == "#{name}-#{version}.gemspec" } &&
|
83
|
+
gems.any? { |g| File.basename(g) == "#{name}-#{version}" }
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# Extending Gem classes to add necessary tracking information
|
2
|
+
module Gem
|
3
|
+
class Dependency
|
4
|
+
def required_by
|
5
|
+
@required_by ||= []
|
6
|
+
end
|
7
|
+
end
|
8
|
+
class Specification
|
9
|
+
def required_by
|
10
|
+
@required_by ||= []
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
module Bundler
|
16
|
+
|
17
|
+
class Resolver
|
18
|
+
|
19
|
+
attr_reader :errors
|
20
|
+
|
21
|
+
def self.resolve(requirements, index = Gem.source_index)
|
22
|
+
result = catch(:success) do
|
23
|
+
resolver = new(index)
|
24
|
+
resolver.resolve(requirements, {})
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
result && result.values
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(index)
|
31
|
+
@errors = {}
|
32
|
+
@index = index
|
33
|
+
end
|
34
|
+
|
35
|
+
def resolve(reqs, activated)
|
36
|
+
throw :success, activated if reqs.empty?
|
37
|
+
|
38
|
+
reqs = reqs.sort_by do |req|
|
39
|
+
activated[req.name] ? 0 : @index.search(req).size
|
40
|
+
end
|
41
|
+
|
42
|
+
activated = activated.dup
|
43
|
+
current = reqs.shift
|
44
|
+
|
45
|
+
if existing = activated[current.name]
|
46
|
+
if current.version_requirements.satisfied_by?(existing.version)
|
47
|
+
@errors.delete(existing.name)
|
48
|
+
resolve(reqs, activated)
|
49
|
+
else
|
50
|
+
@errors[existing.name] = { :gem => existing, :requirement => current }
|
51
|
+
parent = current.required_by.last || existing.required_by.last
|
52
|
+
throw parent.name
|
53
|
+
end
|
54
|
+
else
|
55
|
+
@index.search(current).reverse_each do |spec|
|
56
|
+
resolve_requirement(spec, current, reqs.dup, activated.dup)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def resolve_requirement(spec, requirement, reqs, activated)
|
62
|
+
spec.required_by.replace requirement.required_by
|
63
|
+
activated[spec.name] = spec
|
64
|
+
|
65
|
+
spec.dependencies.each do |dep|
|
66
|
+
next if dep.type == :development
|
67
|
+
dep.required_by << requirement
|
68
|
+
reqs << dep
|
69
|
+
end
|
70
|
+
|
71
|
+
catch(requirement.name) do
|
72
|
+
resolve(reqs, activated)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Bundler
|
2
|
+
class ManifestFileNotFound < StandardError; end
|
3
|
+
|
4
|
+
class ManifestBuilder
|
5
|
+
def self.build(manifest_file, string)
|
6
|
+
builder = new(manifest_file)
|
7
|
+
builder.instance_eval(string)
|
8
|
+
builder
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.load(manifest_file, filename)
|
12
|
+
unless File.exist?(filename)
|
13
|
+
raise ManifestFileNotFound, "#{filename.inspect} does not exist"
|
14
|
+
end
|
15
|
+
string = File.read(filename)
|
16
|
+
build(manifest_file, string)
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(manifest_file)
|
20
|
+
@manifest_file = manifest_file
|
21
|
+
end
|
22
|
+
|
23
|
+
def bundle_path(path)
|
24
|
+
path = Pathname.new(path)
|
25
|
+
@manifest_file.gem_path = (path.relative? ?
|
26
|
+
@manifest_file.root.join(path) : path).expand_path
|
27
|
+
end
|
28
|
+
|
29
|
+
def bin_path(path)
|
30
|
+
path = Pathname.new(path)
|
31
|
+
@manifest_file.bindir = (path.relative? ?
|
32
|
+
@manifest_file.root.join(path) : path).expand_path
|
33
|
+
end
|
34
|
+
|
35
|
+
def disable_rubygems
|
36
|
+
@manifest_file.rubygems = false
|
37
|
+
end
|
38
|
+
|
39
|
+
def disable_system_gems
|
40
|
+
@manifest_file.system_gems = false
|
41
|
+
end
|
42
|
+
|
43
|
+
def source(source)
|
44
|
+
@manifest_file.sources << source
|
45
|
+
@manifest_file.sources.uniq!
|
46
|
+
end
|
47
|
+
|
48
|
+
def sources
|
49
|
+
@manifest_file.sources
|
50
|
+
end
|
51
|
+
|
52
|
+
def gem(name, *args)
|
53
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
54
|
+
version = args.last
|
55
|
+
|
56
|
+
@manifest_file.dependencies << Dependency.new(name, options.merge(:version => version))
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
<% unless @system_gems %>
|
2
|
+
ENV["GEM_HOME"] = "<%= @repository.path %>"
|
3
|
+
ENV["GEM_PATH"] = "<%= @repository.path %>"
|
4
|
+
<% end %>
|
5
|
+
ENV["PATH"] = "<%= @bindir %>:#{ENV["PATH"]}"
|
6
|
+
ENV["RUBYOPT"] = "-r#{__FILE__} #{ENV["RUBYOPT"]}"
|
7
|
+
|
8
|
+
<% load_paths.each do |load_path| %>
|
9
|
+
$LOAD_PATH.unshift "<%= load_path %>"
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<% if @rubygems %>
|
13
|
+
require "rubygems"
|
14
|
+
|
15
|
+
module Bundler
|
16
|
+
|
17
|
+
@bundled_specs = {}
|
18
|
+
<% spec_files.each do |name, path| %>
|
19
|
+
@bundled_specs["<%= name %>"] = eval(File.read("<%= path %>"))
|
20
|
+
@bundled_specs["<%= name %>"].loaded_from = "<%= path %>"
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
def self.add_specs_to_loaded_specs
|
24
|
+
Gem.loaded_specs.merge! @bundled_specs
|
25
|
+
if Gem.respond_to?(:loaded_stacks)
|
26
|
+
@bundled_specs.keys.each { |name| Gem.loaded_stacks[name] = [] }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.add_specs_to_index
|
31
|
+
@bundled_specs.each do |name, spec|
|
32
|
+
Gem.source_index.add_spec spec
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
add_specs_to_loaded_specs
|
37
|
+
add_specs_to_index
|
38
|
+
end
|
39
|
+
|
40
|
+
module Gem
|
41
|
+
def source_index.refresh!
|
42
|
+
super
|
43
|
+
Bundler.add_specs_to_index
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
<% else %>
|
48
|
+
|
49
|
+
$" << "rubygems.rb"
|
50
|
+
module Kernel
|
51
|
+
def gem(*)
|
52
|
+
# Silently ignore calls to gem, since, in theory, everything
|
53
|
+
# is activated correctly already.
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Define all the Gem errors for gems that reference them.
|
58
|
+
module Gem
|
59
|
+
def self.ruby ; <%= Gem.ruby.inspect %> ; end
|
60
|
+
class LoadError < ::LoadError; end
|
61
|
+
class Exception < RuntimeError; end
|
62
|
+
class CommandLineError < Exception; end
|
63
|
+
class DependencyError < Exception; end
|
64
|
+
class DependencyRemovalException < Exception; end
|
65
|
+
class GemNotInHomeException < Exception ; end
|
66
|
+
class DocumentError < Exception; end
|
67
|
+
class EndOfYAMLException < Exception; end
|
68
|
+
class FilePermissionError < Exception; end
|
69
|
+
class FormatException < Exception; end
|
70
|
+
class GemNotFoundException < Exception; end
|
71
|
+
class InstallError < Exception; end
|
72
|
+
class InvalidSpecificationException < Exception; end
|
73
|
+
class OperationNotSupportedError < Exception; end
|
74
|
+
class RemoteError < Exception; end
|
75
|
+
class RemoteInstallationCancelled < Exception; end
|
76
|
+
class RemoteInstallationSkipped < Exception; end
|
77
|
+
class RemoteSourceException < Exception; end
|
78
|
+
class VerificationError < Exception; end
|
79
|
+
class SystemExitException < SystemExit; end
|
80
|
+
end
|
81
|
+
|
82
|
+
<% end %>
|
metadata
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bundler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Yehuda Katz
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-07-29 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: An easy way to vendor gem dependencies
|
17
|
+
email: wycats@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.markdown
|
24
|
+
- LICENSE
|
25
|
+
files:
|
26
|
+
- LICENSE
|
27
|
+
- README.markdown
|
28
|
+
- Rakefile
|
29
|
+
- lib/bundler/cli.rb
|
30
|
+
- lib/bundler/commands/bundle_command.rb
|
31
|
+
- lib/bundler/commands/exec_command.rb
|
32
|
+
- lib/bundler/dependency.rb
|
33
|
+
- lib/bundler/finder.rb
|
34
|
+
- lib/bundler/gem_bundle.rb
|
35
|
+
- lib/bundler/gem_ext.rb
|
36
|
+
- lib/bundler/manifest.rb
|
37
|
+
- lib/bundler/manifest_file.rb
|
38
|
+
- lib/bundler/repository.rb
|
39
|
+
- lib/bundler/resolver.rb
|
40
|
+
- lib/bundler/runtime.rb
|
41
|
+
- lib/bundler/templates/app_script.rb
|
42
|
+
- lib/bundler/templates/environment.rb
|
43
|
+
- lib/bundler/templates/rubygems.rb
|
44
|
+
- lib/bundler.rb
|
45
|
+
- lib/rubygems_plugin.rb
|
46
|
+
has_rdoc: true
|
47
|
+
homepage: http://github.com/wycats/bundler
|
48
|
+
licenses: []
|
49
|
+
|
50
|
+
post_install_message:
|
51
|
+
rdoc_options: []
|
52
|
+
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: "0"
|
60
|
+
version:
|
61
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
62
|
+
requirements:
|
63
|
+
- - ">="
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: "0"
|
66
|
+
version:
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.3.5
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: An easy way to vendor gem dependencies
|
74
|
+
test_files: []
|
75
|
+
|