Vendor the latest version of the bundler
This commit is contained in:
parent
e3f5fd536e
commit
f416f9f0ae
162
railties/lib/vendor/bundler/README.markdown
vendored
Normal file
162
railties/lib/vendor/bundler/README.markdown
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
## Bundler : A gem to bundle gems
|
||||
|
||||
Github: http://github.com/wycats/bundler
|
||||
Mailing list: http://groups.google.com/group/ruby-bundler
|
||||
IRC: #carlhuda on freenode
|
||||
|
||||
## Intro
|
||||
|
||||
Bundler is a tool that manages gem dependencies for your ruby application. It
|
||||
takes a gem manifest file and is able to fetch, download, and install the gems
|
||||
and all child dependencies specified in this manifest. It can manage any update
|
||||
to the gem manifest file and update the bundled gems accordingly. It also lets
|
||||
you run any ruby code in context of the bundled gem environment.
|
||||
|
||||
## Disclaimer
|
||||
|
||||
This project is under rapid development. It is usable today, but there will be
|
||||
many changes in the near future, including to the Gemfile DSL. We will bump up
|
||||
versions with changes though. We greatly appreciate feedback.
|
||||
|
||||
## Installation
|
||||
|
||||
Bundler has no dependencies. Just clone the git repository and install the gem
|
||||
with the following rake task:
|
||||
|
||||
rake install
|
||||
|
||||
## Usage
|
||||
|
||||
Bundler requires a gem manifest file to be created. This should be a file named
|
||||
`Gemfile` located in the root directory of your application. After the manifest
|
||||
has been created, in your shell, cd into your application's directory and run
|
||||
`gem bundle`. This will start the bundling process.
|
||||
|
||||
### Manifest file
|
||||
|
||||
This is where you specify all of your application's dependencies. By default
|
||||
this should be in a file named `Gemfile` located in your application's root
|
||||
directory. The following is an example of a potential `Gemfile`. For more
|
||||
information, please refer to Bundler::ManifestBuilder.
|
||||
|
||||
# Specify a dependency on rails. When the bundler downloads gems,
|
||||
# it will download rails as well as all of rails' dependencies (such as
|
||||
# activerecord, actionpack, etc...)
|
||||
#
|
||||
# At least one dependency must be specified
|
||||
gem "rails"
|
||||
|
||||
# Specify a dependency on rack v.1.0.0. The version is optional. If present,
|
||||
# it can be specified the same way as with rubygems' #gem method.
|
||||
gem "rack", "1.0.0"
|
||||
|
||||
# Specify a dependency rspec, but only activate that gem in the "testing"
|
||||
# environment (read more about environments later). :except is also a valid
|
||||
# option to specify environment restrictions.
|
||||
gem "rspec", :only => :testing
|
||||
|
||||
# Add http://gems.github.com as a source that the bundler will use
|
||||
# to find gems listed in the manifest. By default,
|
||||
# http://gems.rubyforge.org is already added to the list.
|
||||
#
|
||||
# This is an optional setting.
|
||||
source "http://gems.github.com"
|
||||
|
||||
# Specify where the bundled gems should be stashed. This directory will
|
||||
# be a gem repository where all gems are downloaded to and installed to.
|
||||
#
|
||||
# This is an optional setting.
|
||||
# The default is: vendor/gems
|
||||
bundle_path "my/bundled/gems"
|
||||
|
||||
# Specify where gem executables should be copied to.
|
||||
#
|
||||
# This is an optional setting.
|
||||
# The default is: bin
|
||||
bin_path "my/executables"
|
||||
|
||||
# Specify that rubygems should be completely disabled. This means that it
|
||||
# will be impossible to require it and that available gems will be
|
||||
# limited exclusively to gems that have been bundled.
|
||||
#
|
||||
# The default is to automatically require rubygems. There is also a
|
||||
# `disable_system_gems` option that will limit available rubygems to
|
||||
# the ones that have been bundled.
|
||||
disable_rubygems
|
||||
|
||||
### Running Bundler
|
||||
|
||||
Once a manifest file has been created, the only thing that needs to be done
|
||||
is to run the `gem bundle` command anywhere in your application. The script
|
||||
will load the manifest file, resole all the dependencies, download all
|
||||
needed gems, and install them into the specified directory.
|
||||
|
||||
Every time an update is made to the manifest file, run `gem bundle` again to
|
||||
get the changes installed. This will only check the remote sources if your
|
||||
currently installed gems do not satisfy the `Gemfile`. If you want to force
|
||||
checking for updates on the remote sources, use the `--update` option.
|
||||
|
||||
### Running your application
|
||||
|
||||
The easiest way to run your application is to start it with an executable
|
||||
copied to the specified bin directory (by default, simply bin). For example,
|
||||
if the application in question is a rack app, start it with `bin/rackup`.
|
||||
This will automatically set the gem environment correctly.
|
||||
|
||||
Another way to run arbitrary ruby code in context of the bundled gems is to
|
||||
run it with the `gem exec` command. For example:
|
||||
|
||||
gem exec ruby my_ruby_script.rb
|
||||
|
||||
Yet another way is to manually require the environment file first. This is
|
||||
located in `[bundle_path]/environments/default.rb`. For example:
|
||||
|
||||
ruby -r vendor/gems/environment.rb my_ruby_script.rb
|
||||
|
||||
### Using Bundler with Rails today
|
||||
|
||||
It should be possible to use Bundler with Rails today. Here are the steps
|
||||
to follow.
|
||||
|
||||
* In your rails app, create a Gemfile and specify the gems that your
|
||||
application depends on. Make sure to specify rails as well:
|
||||
|
||||
gem "rails", "2.1.2"
|
||||
gem "will_paginate"
|
||||
|
||||
# Optionally, you can disable system gems all together and only
|
||||
# use bundled gems.
|
||||
disable_system_gems
|
||||
|
||||
* Run `gem bundle`
|
||||
|
||||
* You can now use rails if you prepend `gem exec` to every call to `script/*`
|
||||
but that isn't fun.
|
||||
|
||||
* At the top of `config/boot.rb`, add the following line:
|
||||
|
||||
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'vendor', 'gems', 'environment'))
|
||||
|
||||
In theory, this should be enough to get going.
|
||||
|
||||
## To require rubygems or not
|
||||
|
||||
Ideally, no gem would assume the presence of rubygems at runtime. Rubygems provides
|
||||
enough features so that this isn't necessary. However, there are a number of gems
|
||||
that require specific rubygem features.
|
||||
|
||||
If the `disable_rubygems` option is used, Bundler will stub out the most common
|
||||
of these features, but it is possible that things will not go as intended quite
|
||||
yet. So, if you are brave, try your code without rubygems at runtime.
|
||||
|
||||
## Known Issues
|
||||
|
||||
* When a gem points to a git repository, the git repository will be cloned
|
||||
every time Bundler does a gem dependency resolve.
|
||||
|
||||
## Reporting bugs
|
||||
|
||||
Please report all bugs on the github issue tracker for the project located
|
||||
at:
|
||||
|
||||
http://github.com/wycats/bundler/issues/
|
41
railties/lib/vendor/bundler/Rakefile
vendored
41
railties/lib/vendor/bundler/Rakefile
vendored
@ -1,52 +1,57 @@
|
||||
require 'rubygems' unless ENV['NO_RUBYGEMS']
|
||||
require 'rake/gempackagetask'
|
||||
require 'rubygems/specification'
|
||||
require 'date'
|
||||
require 'spec/rake/spectask'
|
||||
|
||||
spec = Gem::Specification.new do |s|
|
||||
s.name = "bundler"
|
||||
s.version = "0.0.1"
|
||||
s.author = "Your Name"
|
||||
s.email = "Your Email"
|
||||
s.homepage = "http://example.com"
|
||||
s.description = s.summary = "A gem that provides..."
|
||||
s.version = "0.5.0.pre"
|
||||
s.author = "Yehuda Katz"
|
||||
s.email = "wycats@gmail.com"
|
||||
s.homepage = "http://github.com/wycats/bundler"
|
||||
s.description = s.summary = "An easy way to vendor gem dependencies"
|
||||
|
||||
s.platform = Gem::Platform::RUBY
|
||||
s.has_rdoc = true
|
||||
s.extra_rdoc_files = ["README", "LICENSE"]
|
||||
s.summary = ""
|
||||
s.extra_rdoc_files = ["README.markdown", "LICENSE"]
|
||||
|
||||
# Uncomment this to add a dependency
|
||||
# s.add_dependency "foo"
|
||||
s.required_rubygems_version = ">= 1.3.5"
|
||||
|
||||
s.bindir = "bin"
|
||||
s.executables = %w( gem_bundler )
|
||||
s.require_path = 'lib'
|
||||
s.files = %w(LICENSE README Rakefile) + Dir.glob("{bin,lib,spec}/**/*")
|
||||
s.files = %w(LICENSE README.markdown Rakefile) + Dir.glob("lib/**/*")
|
||||
end
|
||||
|
||||
task :default => :spec
|
||||
|
||||
begin
|
||||
require 'spec/rake/spectask'
|
||||
rescue LoadError
|
||||
task(:spec) { $stderr.puts '`gem install rspec` to run specs' }
|
||||
else
|
||||
desc "Run specs"
|
||||
Spec::Rake::SpecTask.new do |t|
|
||||
t.spec_files = FileList['spec/**/*_spec.rb']
|
||||
t.spec_files = FileList['spec/**/*_spec.rb'] - FileList['spec/fixtures/**/*_spec.rb']
|
||||
t.spec_opts = %w(-fs --color)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
begin
|
||||
require 'rake/gempackagetask'
|
||||
rescue LoadError
|
||||
task(:gem) { $stderr.puts '`gem install rake` to package gems' }
|
||||
else
|
||||
Rake::GemPackageTask.new(spec) do |pkg|
|
||||
pkg.gem_spec = spec
|
||||
end
|
||||
end
|
||||
|
||||
desc "install the gem locally"
|
||||
task :install => [:package] do
|
||||
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
||||
sh %{gem install pkg/#{spec.name}-#{spec.version}}
|
||||
end
|
||||
|
||||
desc "create a gemspec file"
|
||||
task :make_spec do
|
||||
File.open("#{GEM}.gemspec", "w") do |file|
|
||||
File.open("#{spec.name}.gemspec", "w") do |file|
|
||||
file.puts spec.to_ruby
|
||||
end
|
||||
end
|
40
railties/lib/vendor/bundler/bin/gem_bundler
vendored
40
railties/lib/vendor/bundler/bin/gem_bundler
vendored
@ -1,40 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
require "optparse"
|
||||
require "bundler"
|
||||
|
||||
options = {}
|
||||
|
||||
parser = OptionParser.new do |op|
|
||||
op.banner = "Usage: gem_bundler [OPTIONS] [PATH]"
|
||||
|
||||
op.on("-m", "--manifest MANIFEST") do |manifest|
|
||||
options[:manifest] = manifest
|
||||
end
|
||||
|
||||
op.on_tail("-h", "--help", "Show this message") do
|
||||
puts op
|
||||
exit
|
||||
end
|
||||
end
|
||||
parser.parse!
|
||||
|
||||
options[:path] = ARGV.shift
|
||||
|
||||
unless options[:path]
|
||||
puts parser
|
||||
puts %(
|
||||
[PATH] must be specified
|
||||
)
|
||||
exit
|
||||
end
|
||||
|
||||
unless options[:manifest] && File.exist?(options[:manifest])
|
||||
puts parser
|
||||
puts %(
|
||||
MANIFEST must be a valid manifest file
|
||||
)
|
||||
exit
|
||||
end
|
||||
|
||||
|
||||
Bundler.run(options)
|
26
railties/lib/vendor/bundler/lib/bundler.rb
vendored
26
railties/lib/vendor/bundler/lib/bundler.rb
vendored
@ -1,24 +1,34 @@
|
||||
require 'pathname'
|
||||
require 'logger'
|
||||
require 'set'
|
||||
require 'erb'
|
||||
# Required elements of rubygems
|
||||
require "rubygems/remote_fetcher"
|
||||
require "rubygems/installer"
|
||||
|
||||
require "bundler/gem_bundle"
|
||||
require "bundler/installer"
|
||||
require "bundler/source"
|
||||
require "bundler/finder"
|
||||
require "bundler/gem_specification"
|
||||
require "bundler/gem_ext"
|
||||
require "bundler/resolver"
|
||||
require "bundler/manifest"
|
||||
require "bundler/dependency"
|
||||
require "bundler/runtime"
|
||||
require "bundler/environment"
|
||||
require "bundler/dsl"
|
||||
require "bundler/cli"
|
||||
require "bundler/repository"
|
||||
require "bundler/dependency"
|
||||
|
||||
module Bundler
|
||||
VERSION = "0.5.0"
|
||||
|
||||
def self.run(options = {})
|
||||
manifest = ManifestBuilder.load(options[:path], options[:manifest])
|
||||
manifest.install
|
||||
class << self
|
||||
attr_writer :logger
|
||||
|
||||
def logger
|
||||
@logger ||= begin
|
||||
logger = Logger.new(STDOUT, Logger::INFO)
|
||||
logger.formatter = proc {|_,_,_,msg| "#{msg}\n" }
|
||||
logger
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
52
railties/lib/vendor/bundler/lib/bundler/cli.rb
vendored
52
railties/lib/vendor/bundler/lib/bundler/cli.rb
vendored
@ -1,24 +1,44 @@
|
||||
require "optparse"
|
||||
|
||||
module Bundler
|
||||
module CLI
|
||||
|
||||
def default_manifest
|
||||
current = Pathname.new(Dir.pwd)
|
||||
|
||||
begin
|
||||
manifest = current.join("Gemfile")
|
||||
return manifest.to_s if File.exist?(manifest)
|
||||
current = current.parent
|
||||
end until current.root?
|
||||
nil
|
||||
class CLI
|
||||
def self.run(command, options = {})
|
||||
new(options).run(command)
|
||||
rescue DefaultManifestNotFound => e
|
||||
Bundler.logger.error "Could not find a Gemfile to use"
|
||||
exit 2
|
||||
rescue InvalidEnvironmentName => e
|
||||
Bundler.logger.error "Gemfile error: #{e.message}"
|
||||
exit
|
||||
rescue InvalidRepository => e
|
||||
Bundler.logger.error e.message
|
||||
exit
|
||||
rescue VersionConflict => e
|
||||
Bundler.logger.error e.message
|
||||
exit
|
||||
rescue GemNotFound => e
|
||||
Bundler.logger.error e.message
|
||||
exit
|
||||
end
|
||||
|
||||
module_function :default_manifest
|
||||
|
||||
def default_path
|
||||
Pathname.new(File.dirname(default_manifest)).join("vendor").join("gems").to_s
|
||||
def initialize(options)
|
||||
@options = options
|
||||
@manifest = Bundler::Environment.load(@options[:manifest])
|
||||
end
|
||||
|
||||
module_function :default_path
|
||||
def bundle
|
||||
@manifest.install(@options[:update])
|
||||
end
|
||||
|
||||
def exec
|
||||
@manifest.setup_environment
|
||||
# w0t?
|
||||
super(*@options[:args])
|
||||
end
|
||||
|
||||
def run(command)
|
||||
send(command)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
31
railties/lib/vendor/bundler/lib/bundler/commands/bundle_command.rb
vendored
Normal file
31
railties/lib/vendor/bundler/lib/bundler/commands/bundle_command.rb
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
class Gem::Commands::BundleCommand < Gem::Command
|
||||
|
||||
def initialize
|
||||
super('bundle', 'Create a gem bundle based on your Gemfile', {:manifest => nil, :update => false})
|
||||
|
||||
add_option('-m', '--manifest MANIFEST', "Specify the path to the manifest file") do |manifest, options|
|
||||
options[:manifest] = manifest
|
||||
end
|
||||
|
||||
add_option('-u', '--update', "Force a remote check for newer gems") do
|
||||
options[:update] = true
|
||||
end
|
||||
end
|
||||
|
||||
def usage
|
||||
"#{program_name}"
|
||||
end
|
||||
|
||||
def description # :nodoc:
|
||||
<<-EOF
|
||||
Bundle stuff
|
||||
EOF
|
||||
end
|
||||
|
||||
def execute
|
||||
# Prevent the bundler from getting required unless it is actually being used
|
||||
require 'bundler'
|
||||
Bundler::CLI.run(:bundle, options)
|
||||
end
|
||||
|
||||
end
|
31
railties/lib/vendor/bundler/lib/bundler/commands/exec_command.rb
vendored
Normal file
31
railties/lib/vendor/bundler/lib/bundler/commands/exec_command.rb
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
class Gem::Commands::ExecCommand < Gem::Command
|
||||
|
||||
def initialize
|
||||
super('exec', 'Run a command in context of a gem bundle', {:manifest => nil})
|
||||
|
||||
add_option('-m', '--manifest MANIFEST', "Specify the path to the manifest file") do |manifest, options|
|
||||
options[:manifest] = manifest
|
||||
end
|
||||
end
|
||||
|
||||
def usage
|
||||
"#{program_name} COMMAND"
|
||||
end
|
||||
|
||||
def arguments # :nodoc:
|
||||
"COMMAND command to run in context of the gem bundle"
|
||||
end
|
||||
|
||||
def description # :nodoc:
|
||||
<<-EOF.gsub(' ', '')
|
||||
Run in context of a bundle
|
||||
EOF
|
||||
end
|
||||
|
||||
def execute
|
||||
# Prevent the bundler from getting required unless it is actually being used
|
||||
require 'bundler'
|
||||
Bundler::CLI.run(:exec, options)
|
||||
end
|
||||
|
||||
end
|
@ -1,9 +1,10 @@
|
||||
module Bundler
|
||||
class Dependency
|
||||
class InvalidEnvironmentName < StandardError; end
|
||||
|
||||
class Dependency
|
||||
attr_reader :name, :version, :require_as, :only, :except
|
||||
|
||||
def initialize(name, options = {})
|
||||
def initialize(name, options = {}, &block)
|
||||
options.each do |k, v|
|
||||
options[k.to_s] = v
|
||||
end
|
||||
@ -11,8 +12,13 @@ def initialize(name, options = {})
|
||||
@name = name
|
||||
@version = options["version"] || ">= 0"
|
||||
@require_as = Array(options["require_as"] || name)
|
||||
@only = Array(options["only"]).map {|e| e.to_s } if options["only"]
|
||||
@except = Array(options["except"]).map {|e| e.to_s } if options["except"]
|
||||
@only = options["only"]
|
||||
@except = options["except"]
|
||||
@block = block
|
||||
|
||||
if (@only && @only.include?("rubygems")) || (@except && @except.include?("rubygems"))
|
||||
raise InvalidEnvironmentName, "'rubygems' is not a valid environment name"
|
||||
end
|
||||
end
|
||||
|
||||
def in?(environment)
|
||||
@ -27,9 +33,24 @@ def to_s
|
||||
to_gem_dependency.to_s
|
||||
end
|
||||
|
||||
def require(environment)
|
||||
return unless in?(environment)
|
||||
|
||||
@require_as.each do |file|
|
||||
super(file)
|
||||
end
|
||||
|
||||
@block.call if @block
|
||||
end
|
||||
|
||||
def to_gem_dependency
|
||||
@gem_dep ||= Gem::Dependency.new(name, version)
|
||||
end
|
||||
|
||||
def ==(o)
|
||||
[name, version, require_as, only, except] ==
|
||||
[o.name, o.version, o.require_as, o.only, o.except]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
109
railties/lib/vendor/bundler/lib/bundler/dsl.rb
vendored
Normal file
109
railties/lib/vendor/bundler/lib/bundler/dsl.rb
vendored
Normal file
@ -0,0 +1,109 @@
|
||||
module Bundler
|
||||
class ManifestFileNotFound < StandardError; end
|
||||
|
||||
class Dsl
|
||||
def initialize(environment)
|
||||
@environment = environment
|
||||
@sources = Hash.new { |h,k| h[k] = {} }
|
||||
end
|
||||
|
||||
def bundle_path(path)
|
||||
path = Pathname.new(path)
|
||||
@environment.gem_path = (path.relative? ?
|
||||
@environment.root.join(path) : path).expand_path
|
||||
end
|
||||
|
||||
def bin_path(path)
|
||||
path = Pathname.new(path)
|
||||
@environment.bindir = (path.relative? ?
|
||||
@environment.root.join(path) : path).expand_path
|
||||
end
|
||||
|
||||
def disable_rubygems
|
||||
@environment.rubygems = false
|
||||
end
|
||||
|
||||
def disable_system_gems
|
||||
@environment.system_gems = false
|
||||
end
|
||||
|
||||
def source(source)
|
||||
source = GemSource.new(:uri => source)
|
||||
unless @environment.sources.include?(source)
|
||||
@environment.add_source(source)
|
||||
end
|
||||
end
|
||||
|
||||
def only(env)
|
||||
old, @only = @only, _combine_onlys(env)
|
||||
yield
|
||||
@only = old
|
||||
end
|
||||
|
||||
def except(env)
|
||||
old, @except = @except, _combine_excepts(env)
|
||||
yield
|
||||
@except = old
|
||||
end
|
||||
|
||||
def clear_sources
|
||||
@environment.clear_sources
|
||||
end
|
||||
|
||||
def gem(name, *args)
|
||||
options = args.last.is_a?(Hash) ? args.pop : {}
|
||||
version = args.last
|
||||
|
||||
options[:only] = _combine_onlys(options[:only] || options["only"])
|
||||
options[:except] = _combine_excepts(options[:except] || options["except"])
|
||||
|
||||
dep = Dependency.new(name, options.merge(:version => version))
|
||||
|
||||
# OMG REFACTORZ. KTHX
|
||||
if vendored_at = options[:vendored_at]
|
||||
vendored_at = Pathname.new(vendored_at)
|
||||
vendored_at = @environment.filename.dirname.join(vendored_at) if vendored_at.relative?
|
||||
|
||||
@sources[:directory][vendored_at.to_s] ||= begin
|
||||
source = DirectorySource.new(
|
||||
:name => name,
|
||||
:version => version,
|
||||
:location => vendored_at
|
||||
)
|
||||
@environment.add_priority_source(source)
|
||||
true
|
||||
end
|
||||
elsif git = options[:git]
|
||||
@sources[:git][git] ||= begin
|
||||
source = GitSource.new(
|
||||
:name => name,
|
||||
:version => version,
|
||||
:uri => git,
|
||||
:ref => options[:commit] || options[:tag],
|
||||
:branch => options[:branch]
|
||||
)
|
||||
@environment.add_priority_source(source)
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
@environment.dependencies << dep
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def _combine_onlys(only)
|
||||
return @only unless only
|
||||
only = [only].flatten.compact.uniq.map { |o| o.to_s }
|
||||
only &= @only if @only
|
||||
only
|
||||
end
|
||||
|
||||
def _combine_excepts(except)
|
||||
return @except unless except
|
||||
except = [except].flatten.compact.uniq.map { |o| o.to_s }
|
||||
except |= @except if @except
|
||||
except
|
||||
end
|
||||
end
|
||||
end
|
111
railties/lib/vendor/bundler/lib/bundler/environment.rb
vendored
Normal file
111
railties/lib/vendor/bundler/lib/bundler/environment.rb
vendored
Normal file
@ -0,0 +1,111 @@
|
||||
require "rubygems/source_index"
|
||||
|
||||
module Bundler
|
||||
class DefaultManifestNotFound < StandardError; end
|
||||
|
||||
class Environment
|
||||
attr_reader :filename, :dependencies
|
||||
attr_accessor :rubygems, :system_gems, :gem_path, :bindir
|
||||
|
||||
def self.load(gemfile = nil)
|
||||
gemfile = gemfile ? Pathname.new(gemfile) : default_manifest_file
|
||||
|
||||
unless gemfile.file?
|
||||
raise ManifestFileNotFound, "#{filename.inspect} does not exist"
|
||||
end
|
||||
|
||||
new(gemfile)
|
||||
end
|
||||
|
||||
def self.default_manifest_file
|
||||
current = Pathname.new(Dir.pwd)
|
||||
|
||||
until current.root?
|
||||
filename = current.join("Gemfile")
|
||||
return filename if filename.exist?
|
||||
current = current.parent
|
||||
end
|
||||
|
||||
raise DefaultManifestNotFound
|
||||
end
|
||||
|
||||
def initialize(filename) #, sources, dependencies, bindir, path, rubygems, system_gems)
|
||||
@filename = filename
|
||||
@default_sources = [GemSource.new(:uri => "http://gems.rubyforge.org")]
|
||||
@sources = []
|
||||
@priority_sources = []
|
||||
@dependencies = []
|
||||
@rubygems = true
|
||||
@system_gems = true
|
||||
|
||||
# Evaluate the Gemfile
|
||||
builder = Dsl.new(self)
|
||||
builder.instance_eval(File.read(filename))
|
||||
end
|
||||
|
||||
def install(update = false)
|
||||
begin
|
||||
tmp_path = filename.dirname.join(".tmp")
|
||||
FileUtils.mkdir_p(tmp_path)
|
||||
sources.each { |s| s.tmp_path = tmp_path }
|
||||
repository.install(gem_dependencies, sources,
|
||||
:rubygems => rubygems,
|
||||
:system_gems => system_gems,
|
||||
:manifest => filename,
|
||||
:update => update
|
||||
)
|
||||
ensure
|
||||
FileUtils.rm_rf(tmp_path)
|
||||
end
|
||||
Bundler.logger.info "Done."
|
||||
end
|
||||
|
||||
def setup_environment
|
||||
unless system_gems
|
||||
ENV["GEM_HOME"] = gem_path
|
||||
ENV["GEM_PATH"] = gem_path
|
||||
end
|
||||
ENV["PATH"] = "#{bindir}:#{ENV["PATH"]}"
|
||||
ENV["RUBYOPT"] = "-r#{gem_path}/environment #{ENV["RUBYOPT"]}"
|
||||
end
|
||||
|
||||
def root
|
||||
filename.parent
|
||||
end
|
||||
|
||||
def gem_path
|
||||
@gem_path ||= root.join("vendor", "gems")
|
||||
end
|
||||
|
||||
def bindir
|
||||
@bindir ||= root.join("bin")
|
||||
end
|
||||
|
||||
def sources
|
||||
@priority_sources + @sources + @default_sources
|
||||
end
|
||||
|
||||
def add_source(source)
|
||||
@sources << source
|
||||
end
|
||||
|
||||
def add_priority_source(source)
|
||||
@priority_sources << source
|
||||
end
|
||||
|
||||
def clear_sources
|
||||
@sources.clear
|
||||
@default_sources.clear
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def repository
|
||||
@repository ||= Repository.new(gem_path, bindir)
|
||||
end
|
||||
|
||||
def gem_dependencies
|
||||
@gem_dependencies ||= dependencies.map { |d| d.to_gem_dependency }
|
||||
end
|
||||
end
|
||||
end
|
@ -1,42 +1,51 @@
|
||||
module Bundler
|
||||
# Finder behaves like a rubygems source index in that it responds
|
||||
# to #search. It also resolves a list of dependencies finding the
|
||||
# best possible configuration of gems that satisifes all requirements
|
||||
# without causing any gem activation errors.
|
||||
class Finder
|
||||
|
||||
# Takes an array of gem sources and fetches the full index of
|
||||
# gems from each one. It then combines the indexes together keeping
|
||||
# track of the original source so that any resolved gem can be
|
||||
# fetched from the correct source.
|
||||
#
|
||||
# ==== Parameters
|
||||
# *sources<String>:: URI pointing to the gem repository
|
||||
def initialize(*sources)
|
||||
@results = {}
|
||||
@index = Hash.new { |h,k| h[k] = {} }
|
||||
|
||||
sources.each { |source| fetch(source) }
|
||||
end
|
||||
|
||||
def resolve(*dependencies)
|
||||
resolved = Resolver.resolve(dependencies, self)
|
||||
resolved && GemBundle.new(resolved.all_specs)
|
||||
end
|
||||
|
||||
def fetch(source)
|
||||
deflated = Gem::RemoteFetcher.fetcher.fetch_path("#{source}/Marshal.4.8.Z")
|
||||
inflated = Gem.inflate deflated
|
||||
|
||||
append(Marshal.load(inflated), source)
|
||||
rescue Gem::RemoteFetcher::FetchError => e
|
||||
raise ArgumentError, "#{source} is not a valid source: #{e.message}"
|
||||
end
|
||||
|
||||
def append(index, source)
|
||||
index.gems.values.each do |spec|
|
||||
next unless Gem::Platform.match(spec.platform)
|
||||
spec.source = source
|
||||
@index[spec.name][spec.version] ||= spec
|
||||
end
|
||||
self
|
||||
@cache = {}
|
||||
@index = {}
|
||||
@sources = sources
|
||||
end
|
||||
|
||||
# Searches for a gem that matches the dependency
|
||||
#
|
||||
# ==== Parameters
|
||||
# dependency<Gem::Dependency>:: The gem dependency to search for
|
||||
#
|
||||
# ==== Returns
|
||||
# [Gem::Specification]:: A collection of gem specifications
|
||||
# matching the search
|
||||
def search(dependency)
|
||||
@results[dependency.hash] ||= begin
|
||||
possibilities = @index[dependency.name].values
|
||||
possibilities.select do |spec|
|
||||
@cache[dependency.hash] ||= begin
|
||||
find_by_name(dependency.name).select do |spec|
|
||||
dependency =~ spec
|
||||
end.sort_by {|s| s.version }
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_by_name(name)
|
||||
matches = @index[name] ||= begin
|
||||
versions = {}
|
||||
@sources.reverse_each do |source|
|
||||
versions.merge! source.specs[name] || {}
|
||||
end
|
||||
versions
|
||||
end
|
||||
matches.values
|
||||
end
|
||||
|
||||
end
|
||||
end
|
@ -1,22 +1,10 @@
|
||||
module Bundler
|
||||
class GemBundle < Array
|
||||
def download(directory)
|
||||
FileUtils.mkdir_p(directory)
|
||||
|
||||
current = Dir[File.join(directory, "cache", "*.gem*")]
|
||||
|
||||
each do |spec|
|
||||
cached = File.join(directory, "cache", "#{spec.full_name}.gem")
|
||||
|
||||
unless File.file?(cached)
|
||||
Gem::RemoteFetcher.fetcher.download(spec, spec.source, directory)
|
||||
def download(repository)
|
||||
sort_by {|s| s.full_name.downcase }.each do |spec|
|
||||
spec.source.download(spec, repository)
|
||||
end
|
||||
|
||||
current.delete(cached)
|
||||
end
|
||||
|
||||
current.each { |file| File.delete(file) }
|
||||
|
||||
self
|
||||
end
|
||||
end
|
||||
|
25
railties/lib/vendor/bundler/lib/bundler/gem_ext.rb
vendored
Normal file
25
railties/lib/vendor/bundler/lib/bundler/gem_ext.rb
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
module Gem
|
||||
class Installer
|
||||
def app_script_text(bin_file_name)
|
||||
path = @gem_home
|
||||
template = File.read(File.join(File.dirname(__FILE__), "templates", "app_script.erb"))
|
||||
erb = ERB.new(template, nil, '-')
|
||||
erb.result(binding)
|
||||
end
|
||||
end
|
||||
|
||||
class Specification
|
||||
attr_accessor :source
|
||||
attr_accessor :location
|
||||
|
||||
# Hack to fix github's strange marshal file
|
||||
def specification_version
|
||||
@specification_version && @specification_version.to_i
|
||||
end
|
||||
|
||||
alias full_gem_path_without_location full_gem_path
|
||||
def full_gem_path
|
||||
@location ? @location : full_gem_path_without_location
|
||||
end
|
||||
end
|
||||
end
|
@ -1,10 +0,0 @@
|
||||
module Gem
|
||||
class Specification
|
||||
attribute :source
|
||||
|
||||
def source=(source)
|
||||
@source = source.is_a?(URI) ? source : URI.parse(source)
|
||||
raise ArgumentError, "The source must be an absolute URI" unless @source.absolute?
|
||||
end
|
||||
end
|
||||
end
|
@ -1,44 +0,0 @@
|
||||
module Bundler
|
||||
class Installer
|
||||
def initialize(path)
|
||||
if !File.directory?(path)
|
||||
raise ArgumentError, "#{path} is not a directory"
|
||||
elsif !File.directory?(File.join(path, "cache"))
|
||||
raise ArgumentError, "#{path} is not a valid environment (it does not contain a cache directory)"
|
||||
end
|
||||
|
||||
@path = path
|
||||
@gems = Dir[(File.join(path, "cache", "*.gem"))]
|
||||
end
|
||||
|
||||
def install(options = {})
|
||||
bin_dir = options[:bin_dir] ||= File.join(@path, "bin")
|
||||
|
||||
specs = Dir[File.join(@path, "specifications", "*.gemspec")]
|
||||
gems = Dir[File.join(@path, "gems", "*")]
|
||||
|
||||
@gems.each do |gem|
|
||||
name = File.basename(gem).gsub(/\.gem$/, '')
|
||||
installed = specs.any? { |g| File.basename(g) == "#{name}.gemspec" } &&
|
||||
gems.any? { |g| File.basename(g) == name }
|
||||
|
||||
unless installed
|
||||
installer = Gem::Installer.new(gem, :install_dir => @path,
|
||||
:ignore_dependencies => true,
|
||||
:env_shebang => true,
|
||||
:wrappers => true,
|
||||
:bin_dir => bin_dir)
|
||||
installer.install
|
||||
end
|
||||
|
||||
# remove this spec
|
||||
specs.delete_if { |g| File.basename(g) == "#{name}.gemspec"}
|
||||
gems.delete_if { |g| File.basename(g) == name }
|
||||
end
|
||||
|
||||
(specs + gems).each do |path|
|
||||
FileUtils.rm_rf(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
130
railties/lib/vendor/bundler/lib/bundler/manifest.rb
vendored
130
railties/lib/vendor/bundler/lib/bundler/manifest.rb
vendored
@ -1,130 +0,0 @@
|
||||
require "rubygems/source_index"
|
||||
require "pathname"
|
||||
|
||||
module Bundler
|
||||
class VersionConflict < StandardError; end
|
||||
|
||||
class Manifest
|
||||
attr_reader :sources, :dependencies, :path
|
||||
|
||||
def initialize(sources, dependencies, path)
|
||||
sources.map! {|s| s.is_a?(URI) ? s : URI.parse(s) }
|
||||
@sources, @dependencies, @path = sources, dependencies, Pathname.new(path)
|
||||
end
|
||||
|
||||
def fetch
|
||||
return if all_gems_installed?
|
||||
|
||||
finder = Finder.new(*sources)
|
||||
unless bundle = finder.resolve(*gem_dependencies)
|
||||
gems = @dependencies.map {|d| " #{d.to_s}" }.join("\n")
|
||||
raise VersionConflict, "No compatible versions could be found for:\n#{gems}"
|
||||
end
|
||||
|
||||
bundle.download(@path)
|
||||
end
|
||||
|
||||
def install(options = {})
|
||||
fetch
|
||||
installer = Installer.new(@path)
|
||||
installer.install # options come here
|
||||
create_load_paths_files(File.join(@path, "environments"))
|
||||
create_fake_rubygems(File.join(@path, "environments"))
|
||||
end
|
||||
|
||||
def activate(environment = "default")
|
||||
require File.join(@path, "environments", "#{environment}.rb")
|
||||
end
|
||||
|
||||
def require_all
|
||||
dependencies.each do |dep|
|
||||
dep.require_as.each {|file| require file }
|
||||
end
|
||||
end
|
||||
|
||||
def gems_for(environment)
|
||||
deps = dependencies.select { |d| d.in?(environment) }
|
||||
deps.map! { |d| d.to_gem_dependency }
|
||||
index = Gem::SourceIndex.from_gems_in(File.join(@path, "specifications"))
|
||||
Resolver.resolve(deps, index).all_specs
|
||||
end
|
||||
|
||||
def environments
|
||||
envs = dependencies.map {|dep| Array(dep.only) + Array(dep.except) }.flatten
|
||||
envs << "default"
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def gem_dependencies
|
||||
@gem_dependencies ||= dependencies.map { |d| d.to_gem_dependency }
|
||||
end
|
||||
|
||||
def all_gems_installed?
|
||||
gem_versions = {}
|
||||
|
||||
Dir[File.join(@path, "cache", "*.gem")].each do |file|
|
||||
file =~ /\/([^\/]+)-([\d\.]+)\.gem$/
|
||||
name, version = $1, $2
|
||||
gem_versions[name] = Gem::Version.new(version)
|
||||
end
|
||||
|
||||
gem_dependencies.all? do |dep|
|
||||
gem_versions[dep.name] &&
|
||||
dep.version_requirements.satisfied_by?(gem_versions[dep.name])
|
||||
end
|
||||
end
|
||||
|
||||
def create_load_paths_files(path)
|
||||
FileUtils.mkdir_p(path)
|
||||
environments.each do |environment|
|
||||
gem_specs = gems_for(environment)
|
||||
File.open(File.join(path, "#{environment}.rb"), "w") do |file|
|
||||
file.puts <<-RUBY_EVAL
|
||||
module Bundler
|
||||
def self.rubygems_required
|
||||
#{create_gem_stubs(path, gem_specs)}
|
||||
end
|
||||
end
|
||||
RUBY_EVAL
|
||||
file.puts "$LOAD_PATH.unshift File.expand_path(File.dirname(__FILE__))"
|
||||
load_paths_for_specs(gem_specs).each do |load_path|
|
||||
file.puts "$LOAD_PATH.unshift #{load_path.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_gem_stubs(path, gem_specs)
|
||||
gem_specs.map do |spec|
|
||||
path = File.expand_path(File.join(path, '..', 'specifications', "#{spec.full_name}.gemspec"))
|
||||
%{
|
||||
Gem.loaded_specs["#{spec.name}"] = eval(File.read("#{path}"))
|
||||
}
|
||||
end.join("\n")
|
||||
end
|
||||
|
||||
def create_fake_rubygems(path)
|
||||
File.open(File.join(path, "rubygems.rb"), "w") do |file|
|
||||
file.puts <<-RUBY_EVAL
|
||||
$:.delete File.expand_path(File.dirname(__FILE__))
|
||||
load "rubygems.rb"
|
||||
if defined?(Bundler) && Bundler.respond_to?(:rubygems_required)
|
||||
Bundler.rubygems_required
|
||||
end
|
||||
RUBY_EVAL
|
||||
end
|
||||
end
|
||||
|
||||
def load_paths_for_specs(specs)
|
||||
load_paths = []
|
||||
specs.each do |spec|
|
||||
load_paths << File.join(spec.full_gem_path, spec.bindir) if spec.bindir
|
||||
spec.require_paths.each do |path|
|
||||
load_paths << File.join(spec.full_gem_path, path)
|
||||
end
|
||||
end
|
||||
load_paths
|
||||
end
|
||||
end
|
||||
end
|
151
railties/lib/vendor/bundler/lib/bundler/repository.rb
vendored
Normal file
151
railties/lib/vendor/bundler/lib/bundler/repository.rb
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
require "bundler/repository/gem_repository"
|
||||
require "bundler/repository/directory_repository"
|
||||
|
||||
module Bundler
|
||||
class InvalidRepository < StandardError ; end
|
||||
|
||||
class Repository
|
||||
attr_reader :path
|
||||
|
||||
def initialize(path, bindir)
|
||||
FileUtils.mkdir_p(path)
|
||||
|
||||
@path = Pathname.new(path)
|
||||
@bindir = Pathname.new(bindir)
|
||||
|
||||
@repos = {
|
||||
:gem => Gems.new(@path, @bindir),
|
||||
:directory => Directory.new(@path.join("dirs"), @bindir)
|
||||
}
|
||||
end
|
||||
|
||||
def install(dependencies, sources, options = {})
|
||||
if options[:update] || !satisfies?(dependencies)
|
||||
fetch(dependencies, sources)
|
||||
expand(options)
|
||||
else
|
||||
# Remove any gems that are still around if the Gemfile changed without
|
||||
# requiring new gems to be download (e.g. a line in the Gemfile was
|
||||
# removed)
|
||||
cleanup(Resolver.resolve(dependencies, [source_index]))
|
||||
end
|
||||
configure(options)
|
||||
sync
|
||||
end
|
||||
|
||||
def gems
|
||||
gems = []
|
||||
each_repo do |repo|
|
||||
gems.concat repo.gems
|
||||
end
|
||||
gems
|
||||
end
|
||||
|
||||
def satisfies?(dependencies)
|
||||
index = source_index
|
||||
dependencies.all? { |dep| index.search(dep).size > 0 }
|
||||
end
|
||||
|
||||
def source_index
|
||||
index = Gem::SourceIndex.new
|
||||
|
||||
each_repo do |repo|
|
||||
index.gems.merge!(repo.source_index.gems)
|
||||
end
|
||||
|
||||
index
|
||||
end
|
||||
|
||||
def add_spec(type, spec)
|
||||
@repos[type].add_spec(spec)
|
||||
end
|
||||
|
||||
def download_path_for(type)
|
||||
@repos[type].download_path_for
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def cleanup(bundle)
|
||||
each_repo do |repo|
|
||||
repo.cleanup(bundle)
|
||||
end
|
||||
end
|
||||
|
||||
def each_repo
|
||||
@repos.each do |k, repo|
|
||||
yield repo
|
||||
end
|
||||
end
|
||||
|
||||
def fetch(dependencies, sources)
|
||||
bundle = Resolver.resolve(dependencies, sources)
|
||||
# Cleanup here to remove any gems that could cause problem in the expansion
|
||||
# phase
|
||||
#
|
||||
# TODO: Try to avoid double cleanup
|
||||
cleanup(bundle)
|
||||
bundle.download(self)
|
||||
end
|
||||
|
||||
def sync
|
||||
glob = gems.map { |g| g.executables }.flatten.join(',')
|
||||
|
||||
(Dir[@bindir.join("*")] - Dir[@bindir.join("{#{glob}}")]).each do |file|
|
||||
Bundler.logger.info "Deleting bin file: #{File.basename(file)}"
|
||||
FileUtils.rm_rf(file)
|
||||
end
|
||||
end
|
||||
|
||||
def expand(options)
|
||||
each_repo do |repo|
|
||||
repo.expand(options)
|
||||
end
|
||||
end
|
||||
|
||||
def configure(options)
|
||||
generate_environment(options)
|
||||
end
|
||||
|
||||
def generate_environment(options)
|
||||
FileUtils.mkdir_p(path)
|
||||
|
||||
specs = gems
|
||||
load_paths = load_paths_for_specs(specs)
|
||||
bindir = @bindir.relative_path_from(path).to_s
|
||||
filename = options[:manifest].relative_path_from(path).to_s
|
||||
spec_files = specs.inject({}) do |hash, spec|
|
||||
relative = spec.loaded_from.relative_path_from(@path).to_s
|
||||
hash.merge!(spec.name => relative)
|
||||
end
|
||||
|
||||
File.open(path.join("environment.rb"), "w") do |file|
|
||||
template = File.read(File.join(File.dirname(__FILE__), "templates", "environment.erb"))
|
||||
erb = ERB.new(template, nil, '-')
|
||||
file.puts erb.result(binding)
|
||||
end
|
||||
end
|
||||
|
||||
def load_paths_for_specs(specs)
|
||||
load_paths = []
|
||||
specs.each do |spec|
|
||||
gem_path = Pathname.new(spec.full_gem_path)
|
||||
if spec.bindir
|
||||
load_paths << gem_path.join(spec.bindir).relative_path_from(@path).to_s
|
||||
end
|
||||
spec.require_paths.each do |path|
|
||||
load_paths << gem_path.join(path).relative_path_from(@path).to_s
|
||||
end
|
||||
end
|
||||
load_paths
|
||||
end
|
||||
|
||||
def require_code(file, dep)
|
||||
constraint = case
|
||||
when dep.only then %{ if #{dep.only.inspect}.include?(env)}
|
||||
when dep.except then %{ unless #{dep.except.inspect}.include?(env)}
|
||||
end
|
||||
"require #{file.inspect}#{constraint}"
|
||||
end
|
||||
end
|
||||
end
|
46
railties/lib/vendor/bundler/lib/bundler/repository/directory_repository.rb
vendored
Normal file
46
railties/lib/vendor/bundler/lib/bundler/repository/directory_repository.rb
vendored
Normal file
@ -0,0 +1,46 @@
|
||||
module Bundler
|
||||
class Repository
|
||||
class Directory
|
||||
attr_reader :path, :bindir
|
||||
|
||||
def initialize(path, bindir)
|
||||
@path = path
|
||||
@bindir = bindir
|
||||
|
||||
FileUtils.mkdir_p(path.to_s)
|
||||
end
|
||||
|
||||
def source_index
|
||||
index = Gem::SourceIndex.from_gems_in(@path.join("specifications"))
|
||||
index.each { |n, spec| spec.loaded_from = @path.join("specifications", "#{spec.full_name}.gemspec") }
|
||||
index
|
||||
end
|
||||
|
||||
def gems
|
||||
source_index.gems.values
|
||||
end
|
||||
|
||||
def add_spec(spec)
|
||||
destination = path.join('specifications')
|
||||
destination.mkdir unless destination.exist?
|
||||
|
||||
File.open(destination.join("#{spec.full_name}.gemspec"), 'w') do |f|
|
||||
f.puts spec.to_ruby
|
||||
end
|
||||
end
|
||||
|
||||
def download_path_for
|
||||
@path.join("dirs")
|
||||
end
|
||||
|
||||
# Checks whether a gem is installed
|
||||
def expand(options)
|
||||
# raise NotImplementedError
|
||||
end
|
||||
|
||||
def cleanup(gems)
|
||||
# raise NotImplementedError
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
108
railties/lib/vendor/bundler/lib/bundler/repository/gem_repository.rb
vendored
Normal file
108
railties/lib/vendor/bundler/lib/bundler/repository/gem_repository.rb
vendored
Normal file
@ -0,0 +1,108 @@
|
||||
module Bundler
|
||||
class Repository
|
||||
class Gems
|
||||
attr_reader :path, :bindir
|
||||
|
||||
def initialize(path, bindir)
|
||||
@path = path
|
||||
@bindir = bindir
|
||||
end
|
||||
|
||||
# Returns the source index for all gems installed in the
|
||||
# repository
|
||||
def source_index
|
||||
index = Gem::SourceIndex.from_gems_in(@path.join("specifications"))
|
||||
index.each { |n, spec| spec.loaded_from = @path.join("specifications", "#{spec.full_name}.gemspec") }
|
||||
index
|
||||
end
|
||||
|
||||
def gems
|
||||
source_index.gems.values
|
||||
end
|
||||
|
||||
# Checks whether a gem is installed
|
||||
def expand(options)
|
||||
cached_gems.each do |name, version|
|
||||
unless installed?(name, version)
|
||||
install_cached_gem(name, version, options)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup(gems)
|
||||
glob = gems.map { |g| g.full_name }.join(',')
|
||||
base = path.join("{cache,specifications,gems}")
|
||||
|
||||
(Dir[base.join("*")] - Dir[base.join("{#{glob}}{.gemspec,.gem,}")]).each do |file|
|
||||
if File.basename(file) =~ /\.gem$/
|
||||
name = File.basename(file, '.gem')
|
||||
Bundler.logger.info "Deleting gem: #{name}"
|
||||
end
|
||||
FileUtils.rm_rf(file)
|
||||
end
|
||||
end
|
||||
|
||||
def add_spec(spec)
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def download_path_for
|
||||
path
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def cache_path
|
||||
@path.join("cache")
|
||||
end
|
||||
|
||||
def cache_files
|
||||
Dir[cache_path.join("*.gem")]
|
||||
end
|
||||
|
||||
def cached_gems
|
||||
cache_files.map do |f|
|
||||
full_name = File.basename(f).gsub(/\.gem$/, '')
|
||||
full_name.split(/-(?=[^-]+$)/)
|
||||
end
|
||||
end
|
||||
|
||||
def spec_path
|
||||
@path.join("specifications")
|
||||
end
|
||||
|
||||
def spec_files
|
||||
Dir[spec_path.join("*.gemspec")]
|
||||
end
|
||||
|
||||
def gem_path
|
||||
@path.join("gems")
|
||||
end
|
||||
|
||||
def gem_paths
|
||||
Dir[gem_path.join("*")]
|
||||
end
|
||||
|
||||
def installed?(name, version)
|
||||
spec_files.any? { |g| File.basename(g) == "#{name}-#{version}.gemspec" } &&
|
||||
gem_paths.any? { |g| File.basename(g) == "#{name}-#{version}" }
|
||||
end
|
||||
|
||||
def install_cached_gem(name, version, options = {})
|
||||
cached_gem = cache_path.join("#{name}-#{version}.gem")
|
||||
# TODO: Add a warning if cached_gem is not a file
|
||||
if cached_gem.file?
|
||||
Bundler.logger.info "Installing #{name}-#{version}.gem"
|
||||
installer = Gem::Installer.new(cached_gem.to_s, options.merge(
|
||||
:install_dir => @path,
|
||||
:ignore_dependencies => true,
|
||||
:env_shebang => true,
|
||||
:wrappers => true,
|
||||
:bin_dir => @bindir
|
||||
))
|
||||
installer.install
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
194
railties/lib/vendor/bundler/lib/bundler/resolver.rb
vendored
194
railties/lib/vendor/bundler/lib/bundler/resolver.rb
vendored
@ -1,19 +1,189 @@
|
||||
require 'bundler/resolver/inspect'
|
||||
require 'bundler/resolver/search'
|
||||
require 'bundler/resolver/engine'
|
||||
require 'bundler/resolver/stack'
|
||||
require 'bundler/resolver/state'
|
||||
# This is the latest iteration of the gem dependency resolving algorithm. As of now,
|
||||
# it can resolve (as a success of failure) any set of gem dependencies we throw at it
|
||||
# in a reasonable amount of time. The most iterations I've seen it take is about 150.
|
||||
# The actual implementation of the algorithm is not as good as it could be yet, but that
|
||||
# can come later.
|
||||
|
||||
# Extending Gem classes to add necessary tracking information
|
||||
module Gem
|
||||
class Dependency
|
||||
def required_by
|
||||
@required_by ||= []
|
||||
end
|
||||
end
|
||||
class Specification
|
||||
def required_by
|
||||
@required_by ||= []
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
module Bundler
|
||||
module Resolver
|
||||
def self.resolve(deps, source_index = Gem.source_index, logger = nil)
|
||||
unless logger
|
||||
logger = Logger.new($stderr)
|
||||
logger.datetime_format = ""
|
||||
logger.level = ENV["GEM_RESOLVER_DEBUG"] ? Logger::DEBUG : Logger::ERROR
|
||||
class GemNotFound < StandardError; end
|
||||
class VersionConflict < StandardError; end
|
||||
|
||||
class Resolver
|
||||
|
||||
attr_reader :errors
|
||||
|
||||
# Figures out the best possible configuration of gems that satisfies
|
||||
# the list of passed dependencies and any child dependencies without
|
||||
# causing any gem activation errors.
|
||||
#
|
||||
# ==== Parameters
|
||||
# *dependencies<Gem::Dependency>:: The list of dependencies to resolve
|
||||
#
|
||||
# ==== Returns
|
||||
# <GemBundle>,nil:: If the list of dependencies can be resolved, a
|
||||
# collection of gemspecs is returned. Otherwise, nil is returned.
|
||||
def self.resolve(requirements, sources)
|
||||
Bundler.logger.info "Calculating dependencies..."
|
||||
|
||||
resolver = new(sources)
|
||||
result = catch(:success) do
|
||||
resolver.resolve(requirements, {})
|
||||
output = resolver.errors.inject("") do |o, (conflict, (origin, requirement))|
|
||||
o << " Conflict on: #{conflict.inspect}:\n"
|
||||
o << " * #{conflict} (#{origin.version}) activated by #{origin.required_by.first}\n"
|
||||
o << " * #{requirement} required by #{requirement.required_by.first}\n"
|
||||
o << " All possible versions of origin requirements conflict."
|
||||
end
|
||||
raise VersionConflict, "No compatible versions could be found for required dependencies:\n #{output}"
|
||||
nil
|
||||
end
|
||||
result && GemBundle.new(result.values)
|
||||
end
|
||||
|
||||
Engine.resolve(deps, source_index, logger)
|
||||
def initialize(sources)
|
||||
@errors = {}
|
||||
@stack = []
|
||||
@specs = Hash.new { |h,k| h[k] = {} }
|
||||
@cache = {}
|
||||
@index = {}
|
||||
|
||||
sources.reverse_each do |source|
|
||||
source.gems.values.each do |spec|
|
||||
# TMP HAX FOR OPTZ
|
||||
spec.source = source
|
||||
next unless Gem::Platform.match(spec.platform)
|
||||
@specs[spec.name][spec.version] = spec
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def resolve(reqs, activated)
|
||||
# If the requirements are empty, then we are in a success state. Aka, all
|
||||
# gem dependencies have been resolved.
|
||||
throw :success, activated if reqs.empty?
|
||||
|
||||
# Sort requirements so that the ones that are easiest to resolve are first.
|
||||
# Easiest to resolve is defined by: Is this gem already activated? Otherwise,
|
||||
# check the number of child dependencies this requirement has.
|
||||
reqs = reqs.sort_by do |req|
|
||||
activated[req.name] ? 0 : search(req).size
|
||||
end
|
||||
|
||||
activated = activated.dup
|
||||
# Pull off the first requirement so that we can resolve it
|
||||
current = reqs.shift
|
||||
|
||||
# Check if the gem has already been activated, if it has, we will make sure
|
||||
# that the currently activated gem satisfies the requirement.
|
||||
if existing = activated[current.name]
|
||||
if current.version_requirements.satisfied_by?(existing.version)
|
||||
@errors.delete(existing.name)
|
||||
# Since the current requirement is satisfied, we can continue resolving
|
||||
# the remaining requirements.
|
||||
resolve(reqs, activated)
|
||||
else
|
||||
@errors[existing.name] = [existing, current]
|
||||
# Since the current requirement conflicts with an activated gem, we need
|
||||
# to backtrack to the current requirement's parent and try another version
|
||||
# of it (maybe the current requirement won't be present anymore). If the
|
||||
# current requirement is a root level requirement, we need to jump back to
|
||||
# where the conflicting gem was activated.
|
||||
parent = current.required_by.last || existing.required_by.last
|
||||
# We track the spot where the current gem was activated because we need
|
||||
# to keep a list of every spot a failure happened.
|
||||
throw parent.name, existing.required_by.last.name
|
||||
end
|
||||
else
|
||||
# There are no activated gems for the current requirement, so we are going
|
||||
# to find all gems that match the current requirement and try them in decending
|
||||
# order. We also need to keep a set of all conflicts that happen while trying
|
||||
# this gem. This is so that if no versions work, we can figure out the best
|
||||
# place to backtrack to.
|
||||
conflicts = Set.new
|
||||
|
||||
# Fetch all gem versions matching the requirement
|
||||
#
|
||||
# TODO: Warn / error when no matching versions are found.
|
||||
matching_versions = search(current)
|
||||
|
||||
if matching_versions.empty?
|
||||
if current.required_by.empty?
|
||||
raise GemNotFound, "Could not find gem '#{current}' in any of the sources"
|
||||
end
|
||||
Bundler.logger.warn "Could not find gem '#{current}' (required by '#{current.required_by.last}') in any of the sources"
|
||||
end
|
||||
|
||||
matching_versions.reverse_each do |spec|
|
||||
conflict = resolve_requirement(spec, current, reqs.dup, activated.dup)
|
||||
conflicts << conflict if conflict
|
||||
end
|
||||
# If the current requirement is a root level gem and we have conflicts, we
|
||||
# can figure out the best spot to backtrack to.
|
||||
if current.required_by.empty? && !conflicts.empty?
|
||||
# Check the current "catch" stack for the first one that is included in the
|
||||
# conflicts set. That is where the parent of the conflicting gem was required.
|
||||
# By jumping back to this spot, we can try other version of the parent of
|
||||
# the conflicting gem, hopefully finding a combination that activates correctly.
|
||||
@stack.reverse_each do |savepoint|
|
||||
if conflicts.include?(savepoint)
|
||||
throw savepoint
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_requirement(spec, requirement, reqs, activated)
|
||||
# We are going to try activating the spec. We need to keep track of stack of
|
||||
# requirements that got us to the point of activating this gem.
|
||||
spec.required_by.replace requirement.required_by
|
||||
spec.required_by << requirement
|
||||
|
||||
activated[spec.name] = spec
|
||||
|
||||
# Now, we have to loop through all child dependencies and add them to our
|
||||
# array of requirements.
|
||||
spec.dependencies.each do |dep|
|
||||
next if dep.type == :development
|
||||
dep.required_by << requirement
|
||||
reqs << dep
|
||||
end
|
||||
|
||||
# We create a savepoint and mark it by the name of the requirement that caused
|
||||
# the gem to be activated. If the activated gem ever conflicts, we are able to
|
||||
# jump back to this point and try another version of the gem.
|
||||
length = @stack.length
|
||||
@stack << requirement.name
|
||||
retval = catch(requirement.name) do
|
||||
resolve(reqs, activated)
|
||||
end
|
||||
# Since we're doing a lot of throw / catches. A push does not necessarily match
|
||||
# up to a pop. So, we simply slice the stack back to what it was before the catch
|
||||
# block.
|
||||
@stack.slice!(length..-1)
|
||||
retval
|
||||
end
|
||||
|
||||
def search(dependency)
|
||||
@cache[dependency.hash] ||= begin
|
||||
@specs[dependency.name].values.select do |spec|
|
||||
dependency =~ spec
|
||||
end.sort_by {|s| s.version }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,61 +0,0 @@
|
||||
module Bundler
|
||||
module Resolver
|
||||
module Builders
|
||||
def build_index(&block)
|
||||
index = Gem::SourceIndex.new
|
||||
IndexBuilder.run(index, &block) if block_given?
|
||||
index
|
||||
end
|
||||
|
||||
def build_spec(name, version, &block)
|
||||
spec = Gem::Specification.new
|
||||
spec.instance_variable_set(:@name, name)
|
||||
spec.instance_variable_set(:@version, Gem::Version.new(version))
|
||||
DepBuilder.run(spec, &block) if block_given?
|
||||
spec
|
||||
end
|
||||
|
||||
def build_dep(name, requirements, type = :runtime)
|
||||
Gem::Dependency.new(name, requirements, type)
|
||||
end
|
||||
|
||||
class IndexBuilder
|
||||
include Builders
|
||||
|
||||
def self.run(index, &block)
|
||||
new(index).run(&block)
|
||||
end
|
||||
|
||||
def initialize(index)
|
||||
@index = index
|
||||
end
|
||||
|
||||
def run(&block)
|
||||
instance_eval(&block)
|
||||
end
|
||||
|
||||
def add_spec(*args, &block)
|
||||
@index.add_spec(build_spec(*args, &block))
|
||||
end
|
||||
end
|
||||
|
||||
class DepBuilder
|
||||
def self.run(spec, &block)
|
||||
new(spec).run(&block)
|
||||
end
|
||||
|
||||
def initialize(spec)
|
||||
@spec = spec
|
||||
end
|
||||
|
||||
def run(&block)
|
||||
instance_eval(&block)
|
||||
end
|
||||
|
||||
def runtime(name, requirements)
|
||||
@spec.add_runtime_dependency(name, requirements)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,38 +0,0 @@
|
||||
module Bundler
|
||||
module Resolver
|
||||
class ClosedSet < Set
|
||||
end
|
||||
|
||||
class Engine
|
||||
include Search, Inspect
|
||||
|
||||
def self.resolve(deps, source_index, logger)
|
||||
new(deps, source_index, logger).resolve
|
||||
end
|
||||
|
||||
def initialize(deps, source_index, logger)
|
||||
@deps, @source_index, @logger = deps, source_index, logger
|
||||
logger.debug "searching for #{gem_resolver_inspect(@deps)}"
|
||||
end
|
||||
attr_reader :deps, :source_index, :logger, :solution
|
||||
|
||||
def resolve
|
||||
state = State.initial(self, [], Stack.new, Stack.new([[[], @deps.dup]]))
|
||||
if solution = search(state)
|
||||
logger.info "got the solution with #{solution.all_specs.size} specs"
|
||||
solution.dump(Logger::INFO)
|
||||
solution
|
||||
end
|
||||
end
|
||||
|
||||
def open
|
||||
@open ||= []
|
||||
end
|
||||
|
||||
def closed
|
||||
@closed ||= ClosedSet.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
@ -1,24 +0,0 @@
|
||||
module Bundler
|
||||
module Resolver
|
||||
module Inspect
|
||||
def gem_resolver_inspect(o)
|
||||
case o
|
||||
when Gem::Specification
|
||||
"#<Spec: #{o.full_name}>"
|
||||
when Array
|
||||
'[' + o.map {|x| gem_resolver_inspect(x)}.join(", ") + ']'
|
||||
when Set
|
||||
gem_resolver_inspect(o.to_a)
|
||||
when Hash
|
||||
'{' + o.map {|k,v| "#{gem_resolver_inspect(k)} => #{gem_resolver_inspect(v)}"}.join(", ") + '}'
|
||||
when Stack
|
||||
o.gem_resolver_inspect
|
||||
else
|
||||
o.inspect
|
||||
end
|
||||
end
|
||||
|
||||
module_function :gem_resolver_inspect
|
||||
end
|
||||
end
|
||||
end
|
@ -1,71 +0,0 @@
|
||||
module Bundler
|
||||
module Resolver
|
||||
module Search
|
||||
def search(initial, max_depth = (1.0 / 0.0))
|
||||
if initial.goal_met?
|
||||
return initial
|
||||
end
|
||||
|
||||
open << initial
|
||||
|
||||
while open.any?
|
||||
current = open.pop
|
||||
closed << current
|
||||
|
||||
new = []
|
||||
current.each_possibility do |attempt|
|
||||
unless closed.include?(attempt)
|
||||
if attempt.goal_met?
|
||||
return attempt
|
||||
elsif attempt.depth < max_depth
|
||||
new << attempt
|
||||
end
|
||||
end
|
||||
end
|
||||
new.reverse.each do |state|
|
||||
open << state
|
||||
end
|
||||
end
|
||||
|
||||
nil
|
||||
end
|
||||
|
||||
def open
|
||||
raise "implement #open in #{self.class}"
|
||||
end
|
||||
|
||||
def closed
|
||||
raise "implement #closed in #{self.class}"
|
||||
end
|
||||
|
||||
module Node
|
||||
def self.included(base)
|
||||
base.extend(ClassMethods)
|
||||
end
|
||||
|
||||
module ClassMethods
|
||||
def initial(*data)
|
||||
new(0, *data)
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(depth)
|
||||
@depth = depth
|
||||
end
|
||||
attr_reader :depth
|
||||
|
||||
def child(*data)
|
||||
self.class.new(@depth + 1, *data)
|
||||
end
|
||||
|
||||
def each_possibility
|
||||
raise "implement #each_possibility on #{self.class}"
|
||||
end
|
||||
|
||||
def goal_met?
|
||||
raise "implement #goal_met? on #{self.class}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,72 +0,0 @@
|
||||
module Bundler
|
||||
module Resolver
|
||||
class Stack
|
||||
def initialize(initial = [])
|
||||
@data = []
|
||||
initial.each do |(path,value)|
|
||||
self[path] = value
|
||||
end
|
||||
end
|
||||
|
||||
def last
|
||||
@data.last
|
||||
end
|
||||
|
||||
def []=(path, value)
|
||||
raise ArgumentError, "#{path.inspect} already has a value" if key?(path)
|
||||
@data << [path.dup, value]
|
||||
end
|
||||
|
||||
def [](path)
|
||||
if key?(path)
|
||||
_, value = @data.find do |(k,v)|
|
||||
k == path
|
||||
end
|
||||
value
|
||||
else
|
||||
raise "No value for #{path.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
def key?(path)
|
||||
@data.any? do |(k,v)|
|
||||
k == path
|
||||
end
|
||||
end
|
||||
|
||||
def each
|
||||
@data.each do |(k,v)|
|
||||
yield k, v
|
||||
end
|
||||
end
|
||||
|
||||
def map
|
||||
@data.map do |(k,v)|
|
||||
yield k, v
|
||||
end
|
||||
end
|
||||
|
||||
def each_value
|
||||
@data.each do |(k,v)|
|
||||
yield v
|
||||
end
|
||||
end
|
||||
|
||||
def dup
|
||||
self.class.new(@data.dup)
|
||||
end
|
||||
|
||||
def to_s
|
||||
@data.to_s
|
||||
end
|
||||
|
||||
def inspect
|
||||
@data.inspect
|
||||
end
|
||||
|
||||
def gem_resolver_inspect
|
||||
Inspect.gem_resolver_inspect(@data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,172 +0,0 @@
|
||||
module Bundler
|
||||
module Resolver
|
||||
class State
|
||||
include Search::Node, Inspect
|
||||
|
||||
def initialize(depth, engine, path, spec_stack, dep_stack)
|
||||
super(depth)
|
||||
@engine, @path, @spec_stack, @dep_stack = engine, path, spec_stack, dep_stack
|
||||
end
|
||||
attr_reader :path
|
||||
|
||||
def logger
|
||||
@engine.logger
|
||||
end
|
||||
|
||||
def goal_met?
|
||||
logger.info "checking if goal is met"
|
||||
dump
|
||||
no_duplicates?
|
||||
all_deps.all? do |dep|
|
||||
dependency_satisfied?(dep)
|
||||
end
|
||||
end
|
||||
|
||||
def no_duplicates?
|
||||
names = []
|
||||
all_specs.each do |s|
|
||||
if names.include?(s.name)
|
||||
raise "somehow got duplicates for #{s.name}"
|
||||
end
|
||||
names << s.name
|
||||
end
|
||||
end
|
||||
|
||||
def dependency_satisfied?(dep)
|
||||
all_specs.any? do |spec|
|
||||
spec.satisfies_requirement?(dep)
|
||||
end
|
||||
end
|
||||
|
||||
def each_possibility(&block)
|
||||
index, dep = remaining_deps.first
|
||||
if dep
|
||||
logger.warn "working on #{dep} for #{spec_name}"
|
||||
handle_dep(index, dep, &block)
|
||||
else
|
||||
logger.warn "no dependencies left for #{spec_name}"
|
||||
jump_to_parent(&block)
|
||||
end
|
||||
end
|
||||
|
||||
def handle_dep(index, dep)
|
||||
specs = @engine.source_index.search(dep)
|
||||
|
||||
specs.reverse.each do |s|
|
||||
logger.info "attempting with spec: #{s.full_name}"
|
||||
new_path = @path + [index]
|
||||
new_spec_stack = @spec_stack.dup
|
||||
new_dep_stack = @dep_stack.dup
|
||||
|
||||
new_spec_stack[new_path] = s
|
||||
new_dep_stack[new_path] = s.runtime_dependencies.sort_by do |dep|
|
||||
@engine.source_index.search(dep).size
|
||||
end
|
||||
yield child(@engine, new_path, new_spec_stack, new_dep_stack)
|
||||
end
|
||||
end
|
||||
|
||||
def jump_to_parent
|
||||
if @path.empty?
|
||||
dump
|
||||
logger.warn "at the end"
|
||||
return
|
||||
end
|
||||
|
||||
logger.info "jumping to parent for #{spec_name}"
|
||||
new_path = @path[0..-2]
|
||||
new_spec_stack = @spec_stack.dup
|
||||
new_dep_stack = @dep_stack.dup
|
||||
|
||||
yield child(@engine, new_path, new_spec_stack, new_dep_stack)
|
||||
end
|
||||
|
||||
def remaining_deps
|
||||
remaining_deps_for(@path)
|
||||
end
|
||||
|
||||
def remaining_deps_for(path)
|
||||
no_duplicates?
|
||||
remaining = []
|
||||
@dep_stack[path].each_with_index do |dep,i|
|
||||
remaining << [i, dep] unless all_specs.find {|s| s.name == dep.name}
|
||||
end
|
||||
remaining
|
||||
end
|
||||
|
||||
def deps
|
||||
@dep_stack[@path]
|
||||
end
|
||||
|
||||
def spec
|
||||
@spec_stack[@path]
|
||||
end
|
||||
|
||||
def spec_name
|
||||
@path.empty? ? "<top>" : spec.full_name
|
||||
end
|
||||
|
||||
def all_deps
|
||||
all_deps = Set.new
|
||||
@dep_stack.each_value do |deps|
|
||||
all_deps.merge(deps)
|
||||
end
|
||||
all_deps.to_a
|
||||
end
|
||||
|
||||
def all_specs
|
||||
@spec_stack.map do |path,spec|
|
||||
spec
|
||||
end
|
||||
end
|
||||
|
||||
def dump(level = Logger::DEBUG)
|
||||
logger.add level, "v" * 80
|
||||
logger.add level, "path: #{@path.inspect}"
|
||||
logger.add level, "deps: (#{deps.size})"
|
||||
deps.map do |dep|
|
||||
logger.add level, gem_resolver_inspect(dep)
|
||||
end
|
||||
logger.add level, "remaining_deps: (#{remaining_deps.size})"
|
||||
remaining_deps.each do |dep|
|
||||
logger.add level, gem_resolver_inspect(dep)
|
||||
end
|
||||
logger.add level, "dep_stack: "
|
||||
@dep_stack.each do |path,deps|
|
||||
logger.add level, "#{path.inspect} (#{deps.size})"
|
||||
deps.each do |dep|
|
||||
logger.add level, "-> #{gem_resolver_inspect(dep)}"
|
||||
end
|
||||
end
|
||||
logger.add level, "spec_stack: "
|
||||
@spec_stack.each do |path,spec|
|
||||
logger.add level, "#{path.inspect}: #{gem_resolver_inspect(spec)}"
|
||||
end
|
||||
logger.add level, "^" * 80
|
||||
end
|
||||
|
||||
def to_dot
|
||||
io = StringIO.new
|
||||
io.puts 'digraph deps {'
|
||||
io.puts ' fontname = "Courier";'
|
||||
io.puts ' mincross = 4.0;'
|
||||
io.puts ' ratio = "auto";'
|
||||
dump_to_dot(io, "<top>", [])
|
||||
io.puts '}'
|
||||
io.string
|
||||
end
|
||||
|
||||
def dump_to_dot(io, name, path)
|
||||
@dep_stack[path].each_with_index do |dep,i|
|
||||
new_path = path + [i]
|
||||
spec_name = all_specs.find {|x| x.name == dep.name}.full_name
|
||||
io.puts ' "%s" -> "%s";' % [name, dep.to_s]
|
||||
io.puts ' "%s" -> "%s";' % [dep.to_s, spec_name]
|
||||
if @spec_stack.key?(new_path)
|
||||
dump_to_dot(io, spec_name, new_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -1,39 +1,2 @@
|
||||
module Bundler
|
||||
class ManifestBuilder
|
||||
|
||||
attr_reader :sources
|
||||
|
||||
def self.build(path, string)
|
||||
builder = new(path)
|
||||
builder.instance_eval(string)
|
||||
builder.to_manifest
|
||||
end
|
||||
|
||||
def self.load(path, file)
|
||||
string = File.read(file)
|
||||
build(path, string)
|
||||
end
|
||||
|
||||
def initialize(path)
|
||||
@path = path
|
||||
@sources = %w(http://gems.rubyforge.org)
|
||||
@dependencies = []
|
||||
end
|
||||
|
||||
def to_manifest
|
||||
Manifest.new(@sources, @dependencies, @path)
|
||||
end
|
||||
|
||||
def source(source)
|
||||
@sources << source
|
||||
end
|
||||
|
||||
def gem(name, *args)
|
||||
options = args.last.is_a?(Hash) ? args.pop : {}
|
||||
version = args.last
|
||||
|
||||
@dependencies << Dependency.new(name, options.merge(:version => version))
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
require File.join(File.dirname(__FILE__), "runtime", "dsl")
|
||||
require File.join(File.dirname(__FILE__), "runtime", "dependency")
|
150
railties/lib/vendor/bundler/lib/bundler/source.rb
vendored
Normal file
150
railties/lib/vendor/bundler/lib/bundler/source.rb
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
module Bundler
|
||||
# Represents a source of rubygems. Initially, this is only gem repositories, but
|
||||
# eventually, this will be git, svn, HTTP
|
||||
class Source
|
||||
attr_accessor :tmp_path
|
||||
end
|
||||
|
||||
class GemSource < Source
|
||||
attr_reader :uri
|
||||
|
||||
def initialize(options)
|
||||
@uri = options[:uri]
|
||||
@uri = URI.parse(@uri) unless @uri.is_a?(URI)
|
||||
raise ArgumentError, "The source must be an absolute URI" unless @uri.absolute?
|
||||
end
|
||||
|
||||
def gems
|
||||
@specs ||= fetch_specs
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
uri == other.uri
|
||||
end
|
||||
|
||||
def to_s
|
||||
@uri.to_s
|
||||
end
|
||||
|
||||
class RubygemsRetardation < StandardError; end
|
||||
|
||||
def download(spec, repository)
|
||||
Bundler.logger.info "Downloading #{spec.full_name}.gem"
|
||||
|
||||
destination = repository.download_path_for(:gem)
|
||||
|
||||
unless destination.writable?
|
||||
raise RubygemsRetardation
|
||||
end
|
||||
|
||||
Gem::RemoteFetcher.fetcher.download(spec, uri, repository.download_path_for(:gem))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def fetch_specs
|
||||
Bundler.logger.info "Updating source: #{to_s}"
|
||||
|
||||
deflated = Gem::RemoteFetcher.fetcher.fetch_path("#{uri}/Marshal.4.8.Z")
|
||||
inflated = Gem.inflate deflated
|
||||
|
||||
index = Marshal.load(inflated)
|
||||
index.gems
|
||||
rescue Gem::RemoteFetcher::FetchError => e
|
||||
raise ArgumentError, "#{to_s} is not a valid source: #{e.message}"
|
||||
end
|
||||
end
|
||||
|
||||
class DirectorySource < Source
|
||||
def initialize(options)
|
||||
@name = options[:name]
|
||||
@version = options[:version]
|
||||
@location = options[:location]
|
||||
@require_paths = options[:require_paths] || %w(lib)
|
||||
end
|
||||
|
||||
def gems
|
||||
@gems ||= begin
|
||||
specs = {}
|
||||
|
||||
# Find any gemspec files in the directory and load those specs
|
||||
Dir[@location.join('**', '*.gemspec')].each do |file|
|
||||
path = Pathname.new(file).relative_path_from(@location).dirname
|
||||
spec = eval(File.read(file))
|
||||
spec.require_paths.map! { |p| path.join(p) }
|
||||
specs[spec.full_name] = spec
|
||||
end
|
||||
|
||||
# If a gemspec for the dependency was not found, add it to the list
|
||||
if specs.keys.grep(/^#{Regexp.escape(@name)}/).empty?
|
||||
case
|
||||
when @version.nil?
|
||||
raise ArgumentError, "If you use :at, you must specify the gem" \
|
||||
"and version you wish to stand in for"
|
||||
when !Gem::Version.correct?(@version)
|
||||
raise ArgumentError, "If you use :at, you must specify a gem and" \
|
||||
"version. You specified #{@version} for the version"
|
||||
end
|
||||
|
||||
default = Gem::Specification.new do |s|
|
||||
s.name = @name
|
||||
s.version = Gem::Version.new(@version) if @version
|
||||
end
|
||||
specs[default.full_name] = default
|
||||
end
|
||||
|
||||
specs
|
||||
end
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
# TMP HAX
|
||||
other.is_a?(DirectorySource)
|
||||
end
|
||||
|
||||
def to_s
|
||||
"#{@name} (#{@version}) Located at: '#{@location}'"
|
||||
end
|
||||
|
||||
def download(spec, repository)
|
||||
spec.require_paths.map! { |p| File.join(@location, p) }
|
||||
repository.add_spec(:directory, spec)
|
||||
end
|
||||
end
|
||||
|
||||
class GitSource < DirectorySource
|
||||
def initialize(options)
|
||||
super
|
||||
@uri = options[:uri]
|
||||
@ref = options[:ref]
|
||||
@branch = options[:branch]
|
||||
end
|
||||
|
||||
def gems
|
||||
FileUtils.mkdir_p(tmp_path.join("gitz"))
|
||||
|
||||
# TMP HAX to get the *.gemspec reading to work
|
||||
@location = tmp_path.join("gitz", @name)
|
||||
|
||||
Bundler.logger.info "Cloning git repository at: #{@uri}"
|
||||
`git clone #{@uri} #{@location} --no-hardlinks`
|
||||
|
||||
if @ref
|
||||
Dir.chdir(@location) { `git checkout #{@ref}` }
|
||||
elsif @branch && @branch != "master"
|
||||
Dir.chdir(@location) { `git checkout origin/#{@branch}` }
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def download(spec, repository)
|
||||
dest = repository.download_path_for(:directory).join(@name)
|
||||
spec.require_paths.map! { |p| File.join(dest, p) }
|
||||
repository.add_spec(:directory, spec)
|
||||
if spec.name == @name
|
||||
FileUtils.mkdir_p(dest.dirname)
|
||||
FileUtils.mv(tmp_path.join("gitz", spec.name), dest)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
3
railties/lib/vendor/bundler/lib/bundler/templates/app_script.erb
vendored
Normal file
3
railties/lib/vendor/bundler/lib/bundler/templates/app_script.erb
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
<%= shebang bin_file_name %>
|
||||
require File.join(File.dirname(__FILE__), "<%= path.join("environment").relative_path_from(Pathname.new(bin_dir)) %>")
|
||||
load File.join(File.dirname(__FILE__), "<%= path.join("gems", @spec.full_name, @spec.bindir, bin_file_name).relative_path_from(Pathname.new(bin_dir)) %>")
|
127
railties/lib/vendor/bundler/lib/bundler/templates/environment.erb
vendored
Normal file
127
railties/lib/vendor/bundler/lib/bundler/templates/environment.erb
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
# DO NOT MODIFY THIS FILE
|
||||
module Bundler
|
||||
dir = File.dirname(__FILE__)
|
||||
|
||||
<% unless options[:system_gems] -%>
|
||||
ENV["GEM_HOME"] = dir
|
||||
ENV["GEM_PATH"] = dir
|
||||
<% end -%>
|
||||
ENV["PATH"] = "#{dir}/<%= bindir %>:#{ENV["PATH"]}"
|
||||
ENV["RUBYOPT"] = "-r#{__FILE__} #{ENV["RUBYOPT"]}"
|
||||
|
||||
<% load_paths.each do |load_path| -%>
|
||||
$LOAD_PATH.unshift File.expand_path("#{dir}/<%= load_path %>")
|
||||
<% end -%>
|
||||
|
||||
@gemfile = "#{dir}/<%= filename %>"
|
||||
|
||||
<% if options[:rubygems] -%>
|
||||
require "rubygems"
|
||||
|
||||
@bundled_specs = {}
|
||||
<% spec_files.each do |name, path| -%>
|
||||
@bundled_specs["<%= name %>"] = eval(File.read("#{dir}/<%= path %>"))
|
||||
@bundled_specs["<%= name %>"].loaded_from = "#{dir}/<%= path %>"
|
||||
<% end -%>
|
||||
|
||||
def self.add_specs_to_loaded_specs
|
||||
Gem.loaded_specs.merge! @bundled_specs
|
||||
end
|
||||
|
||||
def self.add_specs_to_index
|
||||
@bundled_specs.each do |name, spec|
|
||||
Gem.source_index.add_spec spec
|
||||
end
|
||||
end
|
||||
|
||||
add_specs_to_loaded_specs
|
||||
add_specs_to_index
|
||||
<% end -%>
|
||||
|
||||
def self.require_env(env = nil)
|
||||
context = Class.new do
|
||||
def initialize(env) @env = env && env.to_s ; end
|
||||
def method_missing(*) ; end
|
||||
def only(env)
|
||||
old, @only = @only, _combine_onlys(env)
|
||||
yield
|
||||
@only = old
|
||||
end
|
||||
def except(env)
|
||||
old, @except = @except, _combine_excepts(env)
|
||||
yield
|
||||
@except = old
|
||||
end
|
||||
def gem(name, *args)
|
||||
opt = args.last || {}
|
||||
only = _combine_onlys(opt[:only] || opt["only"])
|
||||
except = _combine_excepts(opt[:except] || opt["except"])
|
||||
files = opt[:require_as] || opt["require_as"] || name
|
||||
|
||||
return unless !only || only.any? {|e| e == @env }
|
||||
return if except && except.any? {|e| e == @env }
|
||||
|
||||
files.each { |f| require f }
|
||||
yield if block_given?
|
||||
true
|
||||
end
|
||||
private
|
||||
def _combine_onlys(only)
|
||||
return @only unless only
|
||||
only = [only].flatten.compact.uniq.map { |o| o.to_s }
|
||||
only &= @only if @only
|
||||
only
|
||||
end
|
||||
def _combine_excepts(except)
|
||||
return @except unless except
|
||||
except = [except].flatten.compact.uniq.map { |o| o.to_s }
|
||||
except |= @except if @except
|
||||
except
|
||||
end
|
||||
end
|
||||
context.new(env && env.to_s).instance_eval(File.read(@gemfile))
|
||||
end
|
||||
end
|
||||
|
||||
<% if options[:rubygems] -%>
|
||||
module Gem
|
||||
def source_index.refresh!
|
||||
super
|
||||
Bundler.add_specs_to_index
|
||||
end
|
||||
end
|
||||
<% else -%>
|
||||
$" << "rubygems.rb"
|
||||
|
||||
module Kernel
|
||||
def gem(*)
|
||||
# Silently ignore calls to gem, since, in theory, everything
|
||||
# is activated correctly already.
|
||||
end
|
||||
end
|
||||
|
||||
# Define all the Gem errors for gems that reference them.
|
||||
module Gem
|
||||
def self.ruby ; <%= Gem.ruby.inspect %> ; end
|
||||
class LoadError < ::LoadError; end
|
||||
class Exception < RuntimeError; end
|
||||
class CommandLineError < Exception; end
|
||||
class DependencyError < Exception; end
|
||||
class DependencyRemovalException < Exception; end
|
||||
class GemNotInHomeException < Exception ; end
|
||||
class DocumentError < Exception; end
|
||||
class EndOfYAMLException < Exception; end
|
||||
class FilePermissionError < Exception; end
|
||||
class FormatException < Exception; end
|
||||
class GemNotFoundException < Exception; end
|
||||
class InstallError < Exception; end
|
||||
class InvalidSpecificationException < Exception; end
|
||||
class OperationNotSupportedError < Exception; end
|
||||
class RemoteError < Exception; end
|
||||
class RemoteInstallationCancelled < Exception; end
|
||||
class RemoteInstallationSkipped < Exception; end
|
||||
class RemoteSourceException < Exception; end
|
||||
class VerificationError < Exception; end
|
||||
class SystemExitException < SystemExit; end
|
||||
end
|
||||
<% end -%>
|
Loading…
Reference in New Issue
Block a user