bundler 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of bundler might be problematic. Click here for more details.
- data/README.markdown +22 -2
- data/lib/bundler.rb +1 -1
- data/lib/bundler/cli.rb +14 -7
- data/lib/bundler/commands/bundle_command.rb +17 -0
- data/lib/bundler/commands/exec_command.rb +5 -0
- data/lib/bundler/dependency.rb +11 -4
- data/lib/bundler/dsl.rb +97 -38
- data/lib/bundler/environment.rb +35 -12
- data/lib/bundler/repository.rb +78 -37
- data/lib/bundler/resolver.rb +39 -17
- data/lib/bundler/source.rb +95 -65
- data/lib/bundler/templates/environment.erb +31 -15
- metadata +2 -2
    
        data/README.markdown
    CHANGED
    
    | @@ -175,11 +175,31 @@ will be compiled for the target platform without requiring that the | |
| 175 175 | 
             
            Assuming a Rails app with Bundler's standard setup, add something like
         | 
| 176 176 | 
             
            this to your top-level `.gitignore` to only keep the cache:
         | 
| 177 177 |  | 
| 178 | 
            -
                vendor/gems | 
| 178 | 
            +
                vendor/gems/*
         | 
| 179 179 | 
             
                !vendor/gems/cache/
         | 
| 180 180 |  | 
| 181 181 | 
             
            Make sure that you explicitly `git add vendor/gems/cache` before you commit.
         | 
| 182 182 |  | 
| 183 | 
            +
            ### Gems with compile-time options
         | 
| 184 | 
            +
             | 
| 185 | 
            +
            Some gems require you to pass compile-time options to the gem install command.
         | 
| 186 | 
            +
            For instance, to install mysql, you might do:
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                gem install mysql -- --with-mysql-config=/usr/local/lib/mysql
         | 
| 189 | 
            +
             | 
| 190 | 
            +
            You can pass these options to the bundler by creating a YAML file containing
         | 
| 191 | 
            +
            the options in question:
         | 
| 192 | 
            +
             | 
| 193 | 
            +
                mysql:
         | 
| 194 | 
            +
                  mysql-config: /usr/local/lib/mysql
         | 
| 195 | 
            +
             | 
| 196 | 
            +
            You can then point the bundler at the file:
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                gem bundle --build-options build_options.yml
         | 
| 199 | 
            +
             | 
| 200 | 
            +
            In general, you will want to keep the build options YAML out of version control,
         | 
| 201 | 
            +
            and provide the appropriate options for the system in question.
         | 
| 202 | 
            +
             | 
| 183 203 | 
             
            ### Running your application
         | 
| 184 204 |  | 
| 185 205 | 
             
            The easiest way to run your application is to start it with an executable
         | 
| @@ -196,7 +216,7 @@ You can use `gem exec bash` to enter a shell that will run all binaries in | |
| 196 216 | 
             
            the current context.
         | 
| 197 217 |  | 
| 198 218 | 
             
            Yet another way is to manually require the environment file first. This is
         | 
| 199 | 
            -
            located in `[bundle_path]/ | 
| 219 | 
            +
            located in `[bundle_path]/gems/environment.rb`. For example:
         | 
| 200 220 |  | 
| 201 221 | 
             
                ruby -r vendor/gems/environment.rb my_ruby_script.rb
         | 
| 202 222 |  | 
    
        data/lib/bundler.rb
    CHANGED
    
    
    
        data/lib/bundler/cli.rb
    CHANGED
    
    | @@ -25,33 +25,40 @@ module Bundler | |
| 25 25 | 
             
                rescue SourceNotCached => e
         | 
| 26 26 | 
             
                  Bundler.logger.error e.message
         | 
| 27 27 | 
             
                  exit 9
         | 
| 28 | 
            +
                rescue ManifestFileNotFound => e
         | 
| 29 | 
            +
                  Bundler.logger.error e.message
         | 
| 30 | 
            +
                  exit 10
         | 
| 28 31 | 
             
                end
         | 
| 29 32 |  | 
| 30 33 | 
             
                def initialize(options)
         | 
| 31 34 | 
             
                  @options = options
         | 
| 32 | 
            -
                  @ | 
| 35 | 
            +
                  @environment = Bundler::Environment.load(@options[:manifest])
         | 
| 33 36 | 
             
                end
         | 
| 34 37 |  | 
| 35 38 | 
             
                def bundle
         | 
| 36 | 
            -
                  @ | 
| 39 | 
            +
                  @environment.install(@options)
         | 
| 37 40 | 
             
                end
         | 
| 38 41 |  | 
| 39 42 | 
             
                def cache
         | 
| 40 | 
            -
                  @ | 
| 43 | 
            +
                  @environment.cache(@options)
         | 
| 41 44 | 
             
                end
         | 
| 42 45 |  | 
| 43 46 | 
             
                def prune
         | 
| 44 | 
            -
                  @ | 
| 47 | 
            +
                  @environment.prune(@options)
         | 
| 45 48 | 
             
                end
         | 
| 46 49 |  | 
| 47 50 | 
             
                def list
         | 
| 48 | 
            -
                  @ | 
| 51 | 
            +
                  @environment.list(@options)
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                def list_outdated
         | 
| 55 | 
            +
                  @environment.list_outdated(@options)
         | 
| 49 56 | 
             
                end
         | 
| 50 57 |  | 
| 51 58 | 
             
                def exec
         | 
| 52 | 
            -
                  @ | 
| 59 | 
            +
                  @environment.setup_environment
         | 
| 53 60 | 
             
                  # w0t?
         | 
| 54 | 
            -
                  super( | 
| 61 | 
            +
                  super(*$command)
         | 
| 55 62 | 
             
                end
         | 
| 56 63 |  | 
| 57 64 | 
             
                def run(command)
         | 
| @@ -26,6 +26,21 @@ class Gem::Commands::BundleCommand < Gem::Command | |
| 26 26 | 
             
                add_option('--list', "List all gems that are part of the active bundle") do
         | 
| 27 27 | 
             
                  options[:list] = true
         | 
| 28 28 | 
             
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                add_option('--list-outdated', "List all outdated gems that are part of the active bundle") do
         | 
| 31 | 
            +
                  options[:list_outdated] = true
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                add_option('-b', '--build-options OPTION_FILE', "Specify a path to a yml file with build options for binary gems") do |option_file, options|
         | 
| 35 | 
            +
                  if File.exist?(option_file)
         | 
| 36 | 
            +
                    options[:build_options] = YAML.load_file(option_file)
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
                end
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                add_option('--only ENV', "Only expand the given environment.  To specify multiple environments, use --only multiple times.") do |env, options|
         | 
| 41 | 
            +
                  options[:only] ||= []
         | 
| 42 | 
            +
                  options[:only] << env
         | 
| 43 | 
            +
                end
         | 
| 29 44 | 
             
              end
         | 
| 30 45 |  | 
| 31 46 | 
             
              def usage
         | 
| @@ -47,6 +62,8 @@ Bundle stuff | |
| 47 62 | 
             
                  Bundler::CLI.run(:prune, options)
         | 
| 48 63 | 
             
                elsif options[:list]
         | 
| 49 64 | 
             
                  Bundler::CLI.run(:list, options)
         | 
| 65 | 
            +
                elsif options[:list_outdated]
         | 
| 66 | 
            +
                  Bundler::CLI.run(:list_outdated, options)
         | 
| 50 67 | 
             
                else
         | 
| 51 68 | 
             
                  Bundler::CLI.run(:bundle, options)
         | 
| 52 69 | 
             
                end
         | 
    
        data/lib/bundler/dependency.rb
    CHANGED
    
    | @@ -2,7 +2,7 @@ module Bundler | |
| 2 2 | 
             
              class InvalidEnvironmentName < StandardError; end
         | 
| 3 3 |  | 
| 4 4 | 
             
              class Dependency
         | 
| 5 | 
            -
                attr_reader :name, :version, :require_as, :only, :except
         | 
| 5 | 
            +
                attr_reader :name, :version, :require_as, :only, :except, :bundle
         | 
| 6 6 |  | 
| 7 7 | 
             
                def initialize(name, options = {}, &block)
         | 
| 8 8 | 
             
                  options.each do |k, v|
         | 
| @@ -11,9 +11,10 @@ module Bundler | |
| 11 11 |  | 
| 12 12 | 
             
                  @name       = name
         | 
| 13 13 | 
             
                  @version    = options["version"] || ">= 0"
         | 
| 14 | 
            -
                  @require_as =  | 
| 14 | 
            +
                  @require_as = options["require_as"]
         | 
| 15 15 | 
             
                  @only       = options["only"]
         | 
| 16 16 | 
             
                  @except     = options["except"]
         | 
| 17 | 
            +
                  @bundle     = options.key?("bundle") ? options["bundle"] : true
         | 
| 17 18 | 
             
                  @block      = block
         | 
| 18 19 |  | 
| 19 20 | 
             
                  if (@only && @only.include?("rubygems")) || (@except && @except.include?("rubygems"))
         | 
| @@ -36,8 +37,14 @@ module Bundler | |
| 36 37 | 
             
                def require_env(environment)
         | 
| 37 38 | 
             
                  return unless in?(environment)
         | 
| 38 39 |  | 
| 39 | 
            -
                  @require_as | 
| 40 | 
            -
                    require file
         | 
| 40 | 
            +
                  if @require_as
         | 
| 41 | 
            +
                    Array(@require_as).each { |file| require file }
         | 
| 42 | 
            +
                  else
         | 
| 43 | 
            +
                    begin
         | 
| 44 | 
            +
                      require name
         | 
| 45 | 
            +
                    rescue LoadError
         | 
| 46 | 
            +
                      # Do nothing
         | 
| 47 | 
            +
                    end
         | 
| 41 48 | 
             
                  end
         | 
| 42 49 |  | 
| 43 50 | 
             
                  @block.call if @block
         | 
    
        data/lib/bundler/dsl.rb
    CHANGED
    
    | @@ -2,10 +2,16 @@ module Bundler | |
| 2 2 | 
             
              class ManifestFileNotFound < StandardError; end
         | 
| 3 3 |  | 
| 4 4 | 
             
              class Dsl
         | 
| 5 | 
            +
                def self.evaluate(environment, file)
         | 
| 6 | 
            +
                  builder = new(environment)
         | 
| 7 | 
            +
                  builder.instance_eval(File.read(file.to_s), file.to_s, 1)
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 5 10 | 
             
                def initialize(environment)
         | 
| 6 11 | 
             
                  @environment = environment
         | 
| 7 | 
            -
                  @ | 
| 8 | 
            -
                  @ | 
| 12 | 
            +
                  @directory_sources = []
         | 
| 13 | 
            +
                  @git_sources = {}
         | 
| 14 | 
            +
                  @only, @except, @directory, @git = nil, nil, nil, nil
         | 
| 9 15 | 
             
                end
         | 
| 10 16 |  | 
| 11 17 | 
             
                def bundle_path(path)
         | 
| @@ -35,18 +41,36 @@ module Bundler | |
| 35 41 | 
             
                  end
         | 
| 36 42 | 
             
                end
         | 
| 37 43 |  | 
| 38 | 
            -
                def only(env)
         | 
| 39 | 
            -
                  old, @only = @only,  | 
| 44 | 
            +
                def only(*env)
         | 
| 45 | 
            +
                  old, @only = @only, _combine_only(env)
         | 
| 40 46 | 
             
                  yield
         | 
| 41 47 | 
             
                  @only = old
         | 
| 42 48 | 
             
                end
         | 
| 43 49 |  | 
| 44 | 
            -
                def except(env)
         | 
| 45 | 
            -
                  old, @except = @except,  | 
| 50 | 
            +
                def except(*env)
         | 
| 51 | 
            +
                  old, @except = @except, _combine_except(env)
         | 
| 46 52 | 
             
                  yield
         | 
| 47 53 | 
             
                  @except = old
         | 
| 48 54 | 
             
                end
         | 
| 49 55 |  | 
| 56 | 
            +
                def directory(path, options = {})
         | 
| 57 | 
            +
                  raise DirectorySourceError, "cannot nest calls to directory or git" if @directory || @git
         | 
| 58 | 
            +
                  @directory = DirectorySource.new(options.merge(:location => path))
         | 
| 59 | 
            +
                  @directory_sources << @directory
         | 
| 60 | 
            +
                  @environment.add_priority_source(@directory)
         | 
| 61 | 
            +
                  yield if block_given?
         | 
| 62 | 
            +
                  @directory = nil
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                def git(uri, options = {})
         | 
| 66 | 
            +
                  raise DirectorySourceError, "cannot nest calls to directory or git" if @directory || @git
         | 
| 67 | 
            +
                  @git = GitSource.new(options.merge(:uri => uri))
         | 
| 68 | 
            +
                  @git_sources[uri] = @git
         | 
| 69 | 
            +
                  @environment.add_priority_source(@git)
         | 
| 70 | 
            +
                  yield if block_given?
         | 
| 71 | 
            +
                  @git = nil
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 50 74 | 
             
                def clear_sources
         | 
| 51 75 | 
             
                  @environment.clear_sources
         | 
| 52 76 | 
             
                end
         | 
| @@ -55,37 +79,22 @@ module Bundler | |
| 55 79 | 
             
                  options = args.last.is_a?(Hash) ? args.pop : {}
         | 
| 56 80 | 
             
                  version = args.last
         | 
| 57 81 |  | 
| 58 | 
            -
                   | 
| 59 | 
            -
             | 
| 82 | 
            +
                  if path = options.delete(:vendored_at)
         | 
| 83 | 
            +
                    options[:path] = path
         | 
| 84 | 
            +
                    warn "The :vendored_at option is deprecated. Use :path instead.\nFrom #{caller[0]}"
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  options[:only] = _combine_only(options[:only] || options["only"])
         | 
| 88 | 
            +
                  options[:except] = _combine_except(options[:except] || options["except"])
         | 
| 60 89 |  | 
| 61 90 | 
             
                  dep = Dependency.new(name, options.merge(:version => version))
         | 
| 62 91 |  | 
| 63 | 
            -
                   | 
| 64 | 
            -
             | 
| 65 | 
            -
             | 
| 66 | 
            -
                     | 
| 67 | 
            -
             | 
| 68 | 
            -
                     | 
| 69 | 
            -
                      source = DirectorySource.new(
         | 
| 70 | 
            -
                        :name     => name,
         | 
| 71 | 
            -
                        :version  => version,
         | 
| 72 | 
            -
                        :location => vendored_at
         | 
| 73 | 
            -
                      )
         | 
| 74 | 
            -
                      @environment.add_priority_source(source)
         | 
| 75 | 
            -
                      true
         | 
| 76 | 
            -
                    end
         | 
| 77 | 
            -
                  elsif git = options[:git]
         | 
| 78 | 
            -
                    @sources[:git][git] ||= begin
         | 
| 79 | 
            -
                      source = GitSource.new(
         | 
| 80 | 
            -
                        :name    => name,
         | 
| 81 | 
            -
                        :version => version,
         | 
| 82 | 
            -
                        :uri     => git,
         | 
| 83 | 
            -
                        :ref     => options[:commit] || options[:tag],
         | 
| 84 | 
            -
                        :branch  => options[:branch]
         | 
| 85 | 
            -
                      )
         | 
| 86 | 
            -
                      @environment.add_priority_source(source)
         | 
| 87 | 
            -
                      true
         | 
| 88 | 
            -
                    end
         | 
| 92 | 
            +
                  if options.key?(:bundle) && !options[:bundle]
         | 
| 93 | 
            +
                    # We're using system gems for this one
         | 
| 94 | 
            +
                  elsif @git || options[:git]
         | 
| 95 | 
            +
                    _handle_git_option(name, version, options)
         | 
| 96 | 
            +
                  elsif @directory || options[:path]
         | 
| 97 | 
            +
                    _handle_vendored_option(name, version, options)
         | 
| 89 98 | 
             
                  end
         | 
| 90 99 |  | 
| 91 100 | 
             
                  @environment.dependencies << dep
         | 
| @@ -93,16 +102,66 @@ module Bundler | |
| 93 102 |  | 
| 94 103 | 
             
              private
         | 
| 95 104 |  | 
| 96 | 
            -
                def  | 
| 105 | 
            +
                def _handle_vendored_option(name, version, options)
         | 
| 106 | 
            +
                  dir, path = _find_directory_source(options[:path])
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  if dir
         | 
| 109 | 
            +
                    dir.required_specs << name
         | 
| 110 | 
            +
                    dir.add_spec(path, name, version) if version
         | 
| 111 | 
            +
                  else
         | 
| 112 | 
            +
                    directory options[:path] do
         | 
| 113 | 
            +
                      _handle_vendored_option(name, version, {})
         | 
| 114 | 
            +
                    end
         | 
| 115 | 
            +
                  end
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                def _find_directory_source(path)
         | 
| 119 | 
            +
                  if @directory
         | 
| 120 | 
            +
                    return @directory, Pathname.new(path || '')
         | 
| 121 | 
            +
                  end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                  path = @environment.filename.dirname.join(path)
         | 
| 124 | 
            +
             | 
| 125 | 
            +
                  @directory_sources.each do |s|
         | 
| 126 | 
            +
                    if s.location.expand_path.to_s < path.expand_path.to_s
         | 
| 127 | 
            +
                      return s, path.relative_path_from(s.location)
         | 
| 128 | 
            +
                    end
         | 
| 129 | 
            +
                  end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                  nil
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                def _handle_git_option(name, version, options)
         | 
| 135 | 
            +
                  git    = options[:git].to_s
         | 
| 136 | 
            +
                  ref    = options[:commit] || options[:tag]
         | 
| 137 | 
            +
                  branch = options[:branch]
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                  if source = @git || @git_sources[git]
         | 
| 140 | 
            +
                    if ref && source.ref != ref
         | 
| 141 | 
            +
                      raise GitSourceError, "'#{git}' already specified with ref: #{source.ref}"
         | 
| 142 | 
            +
                    elsif branch && source.branch != branch
         | 
| 143 | 
            +
                      raise GitSourceError, "'#{git}' already specified with branch: #{source.branch}"
         | 
| 144 | 
            +
                    end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                    source.required_specs << name
         | 
| 147 | 
            +
                    source.add_spec(Pathname.new(options[:path] || '.'), name, version) if version
         | 
| 148 | 
            +
                  else
         | 
| 149 | 
            +
                    git(git, :ref => ref, :branch => branch) do
         | 
| 150 | 
            +
                      _handle_git_option(name, version, options)
         | 
| 151 | 
            +
                    end
         | 
| 152 | 
            +
                  end
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                def _combine_only(only)
         | 
| 97 156 | 
             
                  return @only unless only
         | 
| 98 | 
            -
                  only =  | 
| 157 | 
            +
                  only = Array(only).compact.uniq.map { |o| o.to_s }
         | 
| 99 158 | 
             
                  only &= @only if @only
         | 
| 100 159 | 
             
                  only
         | 
| 101 160 | 
             
                end
         | 
| 102 161 |  | 
| 103 | 
            -
                def  | 
| 162 | 
            +
                def _combine_except(except)
         | 
| 104 163 | 
             
                  return @except unless except
         | 
| 105 | 
            -
                  except =  | 
| 164 | 
            +
                  except = Array(except).compact.uniq.map { |o| o.to_s }
         | 
| 106 165 | 
             
                  except |= @except if @except
         | 
| 107 166 | 
             
                  except
         | 
| 108 167 | 
             
                end
         | 
    
        data/lib/bundler/environment.rb
    CHANGED
    
    | @@ -10,11 +10,11 @@ module Bundler | |
| 10 10 | 
             
                attr_accessor :rubygems, :system_gems
         | 
| 11 11 | 
             
                attr_writer :gem_path, :bindir
         | 
| 12 12 |  | 
| 13 | 
            -
                def self.load( | 
| 14 | 
            -
                  gemfile =  | 
| 13 | 
            +
                def self.load(file = nil)
         | 
| 14 | 
            +
                  gemfile = Pathname.new(file || default_manifest_file).expand_path
         | 
| 15 15 |  | 
| 16 16 | 
             
                  unless gemfile.file?
         | 
| 17 | 
            -
                    raise ManifestFileNotFound, "#{ | 
| 17 | 
            +
                    raise ManifestFileNotFound, "Manifest file not found: #{gemfile.to_s.inspect}"
         | 
| 18 18 | 
             
                  end
         | 
| 19 19 |  | 
| 20 20 | 
             
                  new(gemfile)
         | 
| @@ -32,9 +32,9 @@ module Bundler | |
| 32 32 | 
             
                  raise DefaultManifestNotFound
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
| 35 | 
            -
                def initialize(filename) | 
| 35 | 
            +
                def initialize(filename)
         | 
| 36 36 | 
             
                  @filename         = filename
         | 
| 37 | 
            -
                  @default_sources  =  | 
| 37 | 
            +
                  @default_sources  = default_sources
         | 
| 38 38 | 
             
                  @sources          = []
         | 
| 39 39 | 
             
                  @priority_sources = []
         | 
| 40 40 | 
             
                  @dependencies     = []
         | 
| @@ -42,20 +42,27 @@ module Bundler | |
| 42 42 | 
             
                  @system_gems      = true
         | 
| 43 43 |  | 
| 44 44 | 
             
                  # Evaluate the Gemfile
         | 
| 45 | 
            -
                   | 
| 46 | 
            -
                  builder.instance_eval(File.read(filename))
         | 
| 45 | 
            +
                  Dsl.evaluate(self, filename)
         | 
| 47 46 | 
             
                end
         | 
| 48 47 |  | 
| 49 48 | 
             
                def install(options = {})
         | 
| 49 | 
            +
                  if only_envs = options[:only]
         | 
| 50 | 
            +
                    dependencies.reject! { |d| !only_envs.any? {|env| d.in?(env) } }
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                  no_bundle = dependencies.map { |dep| !dep.bundle && dep.name }.compact
         | 
| 54 | 
            +
             | 
| 50 55 | 
             
                  update = options[:update]
         | 
| 51 56 | 
             
                  cached = options[:cached]
         | 
| 52 57 |  | 
| 53 58 | 
             
                  repository.install(gem_dependencies, sources,
         | 
| 54 | 
            -
                    :rubygems | 
| 55 | 
            -
                    :system_gems | 
| 56 | 
            -
                    :manifest | 
| 57 | 
            -
                    :update | 
| 58 | 
            -
                    :cached | 
| 59 | 
            +
                    :rubygems      => rubygems,
         | 
| 60 | 
            +
                    :system_gems   => system_gems,
         | 
| 61 | 
            +
                    :manifest      => filename,
         | 
| 62 | 
            +
                    :update        => options[:update],
         | 
| 63 | 
            +
                    :cached        => options[:cached],
         | 
| 64 | 
            +
                    :build_options => options[:build_options],
         | 
| 65 | 
            +
                    :no_bundle     => no_bundle
         | 
| 59 66 | 
             
                  )
         | 
| 60 67 | 
             
                  Bundler.logger.info "Done."
         | 
| 61 68 | 
             
                end
         | 
| @@ -101,6 +108,18 @@ module Bundler | |
| 101 108 | 
             
                  end
         | 
| 102 109 | 
             
                end
         | 
| 103 110 |  | 
| 111 | 
            +
                def list_outdated(options={})
         | 
| 112 | 
            +
                  outdated_gems = repository.outdated_gems
         | 
| 113 | 
            +
                  if outdated_gems.empty?
         | 
| 114 | 
            +
                    Bundler.logger.info "All gems are up to date."
         | 
| 115 | 
            +
                  else
         | 
| 116 | 
            +
                    Bundler.logger.info "Outdated gems:"
         | 
| 117 | 
            +
                    outdated_gems.each do |name|
         | 
| 118 | 
            +
                      Bundler.logger.info " * #{name}"
         | 
| 119 | 
            +
                    end
         | 
| 120 | 
            +
                  end
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
             | 
| 104 123 | 
             
                def setup_environment
         | 
| 105 124 | 
             
                  unless system_gems
         | 
| 106 125 | 
             
                    ENV["GEM_HOME"] = gem_path
         | 
| @@ -145,6 +164,10 @@ module Bundler | |
| 145 164 |  | 
| 146 165 | 
             
              private
         | 
| 147 166 |  | 
| 167 | 
            +
                def default_sources
         | 
| 168 | 
            +
                  [GemSource.new(:uri => "http://gems.rubyforge.org"), SystemGemSource.instance]
         | 
| 169 | 
            +
                end
         | 
| 170 | 
            +
             | 
| 148 171 | 
             
                def repository
         | 
| 149 172 | 
             
                  @repository ||= Repository.new(gem_path, bindir)
         | 
| 150 173 | 
             
                end
         | 
    
        data/lib/bundler/repository.rb
    CHANGED
    
    | @@ -20,22 +20,31 @@ module Bundler | |
| 20 20 | 
             
                    s.local = options[:cached]
         | 
| 21 21 | 
             
                  end
         | 
| 22 22 |  | 
| 23 | 
            +
                  source_requirements = {}
         | 
| 24 | 
            +
                  options[:no_bundle].each do |name|
         | 
| 25 | 
            +
                    source_requirements[name] = SystemGemSource.instance
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  # Check to see whether the existing cache meets all the requirements
         | 
| 23 29 | 
             
                  begin
         | 
| 24 | 
            -
                    valid = Resolver.resolve(dependencies, [source_index])
         | 
| 30 | 
            +
                    valid = Resolver.resolve(dependencies, [source_index], source_requirements)
         | 
| 25 31 | 
             
                  rescue Bundler::GemNotFound
         | 
| 26 32 | 
             
                  end
         | 
| 27 33 |  | 
| 28 | 
            -
                  if options[:cached]
         | 
| 29 | 
            -
                    sources = sources.select { |s| s.can_be_local? }
         | 
| 30 | 
            -
                  end
         | 
| 34 | 
            +
                  sources = only_local(sources) if options[:cached]
         | 
| 31 35 |  | 
| 36 | 
            +
                  # Check the remote sources if the existing cache does not meet the requirements
         | 
| 37 | 
            +
                  # or the user passed --update
         | 
| 32 38 | 
             
                  if options[:update] || !valid
         | 
| 33 39 | 
             
                    Bundler.logger.info "Calculating dependencies..."
         | 
| 34 | 
            -
                    bundle = Resolver.resolve(dependencies, [@cache] + sources)
         | 
| 40 | 
            +
                    bundle = Resolver.resolve(dependencies, [@cache] + sources, source_requirements)
         | 
| 41 | 
            +
                    download(bundle, options)
         | 
| 35 42 | 
             
                    do_install(bundle, options)
         | 
| 36 43 | 
             
                    valid = bundle
         | 
| 37 44 | 
             
                  end
         | 
| 38 | 
            -
             | 
| 45 | 
            +
             | 
| 46 | 
            +
                  generate_bins(valid, options)
         | 
| 47 | 
            +
                  cleanup(valid, options)
         | 
| 39 48 | 
             
                  configure(valid, options)
         | 
| 40 49 | 
             
                end
         | 
| 41 50 |  | 
| @@ -53,12 +62,14 @@ module Bundler | |
| 53 62 | 
             
                    s.local = true
         | 
| 54 63 | 
             
                  end
         | 
| 55 64 |  | 
| 56 | 
            -
                  sources = sources | 
| 65 | 
            +
                  sources = only_local(sources)
         | 
| 57 66 | 
             
                  bundle = Resolver.resolve(dependencies, [@cache] + sources)
         | 
| 58 | 
            -
                  @cache.gems.each do |name,  | 
| 59 | 
            -
                     | 
| 60 | 
            -
                       | 
| 61 | 
            -
             | 
| 67 | 
            +
                  @cache.gems.each do |name, specs|
         | 
| 68 | 
            +
                    specs.each do |spec|
         | 
| 69 | 
            +
                      unless bundle.any? { |s| s.name == spec.name && s.version == spec.version }
         | 
| 70 | 
            +
                        Bundler.logger.info "Pruning #{spec.name} (#{spec.version}) from the cache"
         | 
| 71 | 
            +
                        FileUtils.rm @path.join("cache", "#{spec.full_name}.gem")
         | 
| 72 | 
            +
                      end
         | 
| 62 73 | 
             
                    end
         | 
| 63 74 | 
             
                  end
         | 
| 64 75 | 
             
                end
         | 
| @@ -67,6 +78,10 @@ module Bundler | |
| 67 78 | 
             
                  source_index.gems.values
         | 
| 68 79 | 
             
                end
         | 
| 69 80 |  | 
| 81 | 
            +
                def outdated_gems
         | 
| 82 | 
            +
                  source_index.outdated.sort
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
             | 
| 70 85 | 
             
                def source_index
         | 
| 71 86 | 
             
                  index = Gem::SourceIndex.from_gems_in(@path.join("specifications"))
         | 
| 72 87 | 
             
                  index.each { |n, spec| spec.loaded_from = @path.join("specifications", "#{spec.full_name}.gemspec") }
         | 
| @@ -79,10 +94,20 @@ module Bundler | |
| 79 94 |  | 
| 80 95 | 
             
              private
         | 
| 81 96 |  | 
| 82 | 
            -
                def  | 
| 83 | 
            -
                   | 
| 97 | 
            +
                def only_local(sources)
         | 
| 98 | 
            +
                  sources.select { |s| s.can_be_local? }
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def download(bundle, options)
         | 
| 102 | 
            +
                  bundle.sort_by {|s| s.full_name.downcase }.each do |spec|
         | 
| 103 | 
            +
                    next if options[:no_bundle].include?(spec.name)
         | 
| 104 | 
            +
                    spec.source.download(spec)
         | 
| 105 | 
            +
                  end
         | 
| 106 | 
            +
                end
         | 
| 84 107 |  | 
| 108 | 
            +
                def do_install(bundle, options)
         | 
| 85 109 | 
             
                  bundle.each do |spec|
         | 
| 110 | 
            +
                    next if options[:no_bundle].include?(spec.name)
         | 
| 86 111 | 
             
                    spec.loaded_from = @path.join("specifications", "#{spec.full_name}.gemspec")
         | 
| 87 112 | 
             
                    # Do nothing if the gem is already expanded
         | 
| 88 113 | 
             
                    next if @path.join("gems", spec.full_name).directory?
         | 
| @@ -96,11 +121,35 @@ module Bundler | |
| 96 121 | 
             
                  end
         | 
| 97 122 | 
             
                end
         | 
| 98 123 |  | 
| 124 | 
            +
                def generate_bins(bundle, options)
         | 
| 125 | 
            +
                  bundle.each do |spec|
         | 
| 126 | 
            +
                    next if options[:no_bundle].include?(spec.name)
         | 
| 127 | 
            +
                    # HAX -- Generate the bin
         | 
| 128 | 
            +
                    bin_dir = @bindir
         | 
| 129 | 
            +
                    path    = @path
         | 
| 130 | 
            +
                    installer = Gem::Installer.allocate
         | 
| 131 | 
            +
                    installer.instance_eval do
         | 
| 132 | 
            +
                      @spec     = spec
         | 
| 133 | 
            +
                      @bin_dir  = bin_dir
         | 
| 134 | 
            +
                      @gem_dir  = path.join("gems", "#{spec.full_name}")
         | 
| 135 | 
            +
                      @gem_home = path
         | 
| 136 | 
            +
                      @wrappers = true
         | 
| 137 | 
            +
                      @format_executable = false
         | 
| 138 | 
            +
                      @env_shebang = false
         | 
| 139 | 
            +
                    end
         | 
| 140 | 
            +
                    installer.generate_bin
         | 
| 141 | 
            +
                  end
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 99 144 | 
             
                def expand_gemfile(spec, options)
         | 
| 100 145 | 
             
                  Bundler.logger.info "Installing #{spec.name} (#{spec.version})"
         | 
| 101 146 |  | 
| 102 147 | 
             
                  gemfile = @path.join("cache", "#{spec.full_name}.gem").to_s
         | 
| 103 148 |  | 
| 149 | 
            +
                  if build_args = options[:build_options] && options[:build_options][spec.name]
         | 
| 150 | 
            +
                    Gem::Command.build_args = build_args.map {|k,v| "--with-#{k}=#{v}"}
         | 
| 151 | 
            +
                  end
         | 
| 152 | 
            +
             | 
| 104 153 | 
             
                  installer = Gem::Installer.new(gemfile, options.merge(
         | 
| 105 154 | 
             
                    :install_dir         => @path,
         | 
| 106 155 | 
             
                    :ignore_dependencies => true,
         | 
| @@ -109,25 +158,14 @@ module Bundler | |
| 109 158 | 
             
                    :bin_dir             => @bindir
         | 
| 110 159 | 
             
                  ))
         | 
| 111 160 | 
             
                  installer.install
         | 
| 161 | 
            +
                ensure
         | 
| 162 | 
            +
                  Gem::Command.build_args = []
         | 
| 112 163 | 
             
                end
         | 
| 113 164 |  | 
| 114 165 | 
             
                def expand_vendored_gem(spec, options)
         | 
| 115 166 | 
             
                  add_spec(spec)
         | 
| 116 167 | 
             
                  FileUtils.mkdir_p(@path.join("gems"))
         | 
| 117 168 | 
             
                  File.symlink(spec.location, @path.join("gems", spec.full_name))
         | 
| 118 | 
            -
             | 
| 119 | 
            -
                  # HAX -- Generate the bin
         | 
| 120 | 
            -
                  bin_dir = @bindir
         | 
| 121 | 
            -
                  path    = @path
         | 
| 122 | 
            -
                  installer = Gem::Installer.allocate
         | 
| 123 | 
            -
                  installer.instance_eval do
         | 
| 124 | 
            -
                    @spec     = spec
         | 
| 125 | 
            -
                    @bin_dir  = bin_dir
         | 
| 126 | 
            -
                    @gem_dir  = path.join("gems", "#{spec.full_name}")
         | 
| 127 | 
            -
                    @gem_home = path
         | 
| 128 | 
            -
                    @wrappers = true
         | 
| 129 | 
            -
                  end
         | 
| 130 | 
            -
                  installer.generate_bin
         | 
| 131 169 | 
             
                end
         | 
| 132 170 |  | 
| 133 171 | 
             
                def add_spec(spec)
         | 
| @@ -139,7 +177,7 @@ module Bundler | |
| 139 177 | 
             
                  end
         | 
| 140 178 | 
             
                end
         | 
| 141 179 |  | 
| 142 | 
            -
                def cleanup(valid)
         | 
| 180 | 
            +
                def cleanup(valid, options)
         | 
| 143 181 | 
             
                  to_delete = gems
         | 
| 144 182 | 
             
                  to_delete.delete_if do |spec|
         | 
| 145 183 | 
             
                    valid.any? { |other| spec.name == other.name && spec.version == other.version }
         | 
| @@ -173,13 +211,9 @@ module Bundler | |
| 173 211 | 
             
                def generate_environment(specs, options)
         | 
| 174 212 | 
             
                  FileUtils.mkdir_p(path)
         | 
| 175 213 |  | 
| 176 | 
            -
                  load_paths = load_paths_for_specs(specs)
         | 
| 214 | 
            +
                  load_paths = load_paths_for_specs(specs, options)
         | 
| 177 215 | 
             
                  bindir     = @bindir.relative_path_from(path).to_s
         | 
| 178 216 | 
             
                  filename   = options[:manifest].relative_path_from(path).to_s
         | 
| 179 | 
            -
                  spec_files = specs.inject({}) do |hash, spec|
         | 
| 180 | 
            -
                    relative = spec.loaded_from.relative_path_from(@path).to_s
         | 
| 181 | 
            -
                    hash.merge!(spec.name => relative)
         | 
| 182 | 
            -
                  end
         | 
| 183 217 |  | 
| 184 218 | 
             
                  File.open(path.join("environment.rb"), "w") do |file|
         | 
| 185 219 | 
             
                    template = File.read(File.join(File.dirname(__FILE__), "templates", "environment.erb"))
         | 
| @@ -188,20 +222,27 @@ module Bundler | |
| 188 222 | 
             
                  end
         | 
| 189 223 | 
             
                end
         | 
| 190 224 |  | 
| 191 | 
            -
                def load_paths_for_specs(specs)
         | 
| 225 | 
            +
                def load_paths_for_specs(specs, options)
         | 
| 192 226 | 
             
                  load_paths = []
         | 
| 193 227 | 
             
                  specs.each do |spec|
         | 
| 228 | 
            +
                    next if options[:no_bundle].include?(spec.name)
         | 
| 194 229 | 
             
                    gem_path = Pathname.new(spec.full_gem_path)
         | 
| 195 | 
            -
                    if spec.bindir
         | 
| 196 | 
            -
                      load_paths << gem_path.join(spec.bindir).relative_path_from(@path).to_s
         | 
| 197 | 
            -
                    end
         | 
| 230 | 
            +
                    load_paths << load_path_for(gem_path, spec.bindir) if spec.bindir
         | 
| 198 231 | 
             
                    spec.require_paths.each do |path|
         | 
| 199 | 
            -
                      load_paths << gem_path | 
| 232 | 
            +
                      load_paths << load_path_for(gem_path, path)
         | 
| 200 233 | 
             
                    end
         | 
| 201 234 | 
             
                  end
         | 
| 202 235 | 
             
                  load_paths
         | 
| 203 236 | 
             
                end
         | 
| 204 237 |  | 
| 238 | 
            +
                def load_path_for(gem_path, path)
         | 
| 239 | 
            +
                  gem_path.join(path).relative_path_from(@path).to_s
         | 
| 240 | 
            +
                end
         | 
| 241 | 
            +
             | 
| 242 | 
            +
                def spec_file_for(spec)
         | 
| 243 | 
            +
                  spec.loaded_from.relative_path_from(@path).to_s
         | 
| 244 | 
            +
                end
         | 
| 245 | 
            +
             | 
| 205 246 | 
             
                def require_code(file, dep)
         | 
| 206 247 | 
             
                  constraint = case
         | 
| 207 248 | 
             
                  when dep.only   then %{ if #{dep.only.inspect}.include?(env)}
         | 
    
        data/lib/bundler/resolver.rb
    CHANGED
    
    | @@ -36,8 +36,8 @@ module Bundler | |
| 36 36 | 
             
                # ==== Returns
         | 
| 37 37 | 
             
                # <GemBundle>,nil:: If the list of dependencies can be resolved, a
         | 
| 38 38 | 
             
                #   collection of gemspecs is returned. Otherwise, nil is returned.
         | 
| 39 | 
            -
                def self.resolve(requirements, sources)
         | 
| 40 | 
            -
                  resolver = new(sources)
         | 
| 39 | 
            +
                def self.resolve(requirements, sources, source_requirements = {})
         | 
| 40 | 
            +
                  resolver = new(sources, source_requirements)
         | 
| 41 41 | 
             
                  result = catch(:success) do
         | 
| 42 42 | 
             
                    resolver.resolve(requirements, {})
         | 
| 43 43 | 
             
                    output = resolver.errors.inject("") do |o, (conflict, (origin, requirement))|
         | 
| @@ -49,22 +49,38 @@ module Bundler | |
| 49 49 | 
             
                    raise VersionConflict, "No compatible versions could be found for required dependencies:\n  #{output}"
         | 
| 50 50 | 
             
                    nil
         | 
| 51 51 | 
             
                  end
         | 
| 52 | 
            -
                   | 
| 52 | 
            +
                  if result
         | 
| 53 | 
            +
                    # Order gems in order of dependencies. Every gem's dependency is at
         | 
| 54 | 
            +
                    # a smaller index in the array.
         | 
| 55 | 
            +
                    ordered = []
         | 
| 56 | 
            +
                    result.values.each do |spec1|
         | 
| 57 | 
            +
                      index = nil
         | 
| 58 | 
            +
                      place = ordered.detect do |spec2|
         | 
| 59 | 
            +
                        spec1.dependencies.any? { |d| d.name == spec2.name }
         | 
| 60 | 
            +
                      end
         | 
| 61 | 
            +
                      place ?
         | 
| 62 | 
            +
                        ordered.insert(ordered.index(place), spec1) :
         | 
| 63 | 
            +
                        ordered << spec1
         | 
| 64 | 
            +
                    end
         | 
| 65 | 
            +
                    ordered.reverse
         | 
| 66 | 
            +
                  end
         | 
| 53 67 | 
             
                end
         | 
| 54 68 |  | 
| 55 | 
            -
                def initialize(sources)
         | 
| 69 | 
            +
                def initialize(sources, source_requirements)
         | 
| 56 70 | 
             
                  @errors = {}
         | 
| 57 71 | 
             
                  @stack  = []
         | 
| 58 | 
            -
                  @specs  = Hash.new { |h,k| h[k] =  | 
| 72 | 
            +
                  @specs  = Hash.new { |h,k| h[k] = [] }
         | 
| 73 | 
            +
                  @by_gem = source_requirements
         | 
| 59 74 | 
             
                  @cache  = {}
         | 
| 60 75 | 
             
                  @index  = {}
         | 
| 61 76 |  | 
| 62 | 
            -
                  sources. | 
| 63 | 
            -
                    source.gems. | 
| 64 | 
            -
                      #  | 
| 65 | 
            -
                       | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 77 | 
            +
                  sources.each do |source|
         | 
| 78 | 
            +
                    source.gems.each do |name, specs|
         | 
| 79 | 
            +
                      # Hack to work with a regular Gem::SourceIndex
         | 
| 80 | 
            +
                      [specs].flatten.compact.each do |spec|
         | 
| 81 | 
            +
                        next if @specs[spec.name].any? { |s| s.version == spec.version }
         | 
| 82 | 
            +
                        @specs[spec.name] << spec
         | 
| 83 | 
            +
                      end
         | 
| 68 84 | 
             
                    end
         | 
| 69 85 | 
             
                  end
         | 
| 70 86 | 
             
                end
         | 
| @@ -74,11 +90,15 @@ module Bundler | |
| 74 90 | 
             
                  # gem dependencies have been resolved.
         | 
| 75 91 | 
             
                  throw :success, activated if reqs.empty?
         | 
| 76 92 |  | 
| 77 | 
            -
                  # Sort  | 
| 78 | 
            -
                  # Easiest to resolve is defined by: | 
| 79 | 
            -
                  #  | 
| 80 | 
            -
                   | 
| 81 | 
            -
             | 
| 93 | 
            +
                  # Sort dependencies so that the ones that are easiest to resolve are first.
         | 
| 94 | 
            +
                  # Easiest to resolve is defined by:
         | 
| 95 | 
            +
                  #   1) Is this gem already activated?
         | 
| 96 | 
            +
                  #   2) Do the version requirements include prereleased gems?
         | 
| 97 | 
            +
                  #   3) Sort by number of gems available in the source.
         | 
| 98 | 
            +
                  reqs = reqs.sort_by do |a|
         | 
| 99 | 
            +
                    [ activated[a.name] ? 0 : 1,
         | 
| 100 | 
            +
                      a.version_requirements.prerelease? ? 0 : 1,
         | 
| 101 | 
            +
                      activated[a.name] ? 0 : search(a).size ]
         | 
| 82 102 | 
             
                  end
         | 
| 83 103 |  | 
| 84 104 | 
             
                  activated = activated.dup
         | 
| @@ -178,7 +198,9 @@ module Bundler | |
| 178 198 |  | 
| 179 199 | 
             
                def search(dependency)
         | 
| 180 200 | 
             
                  @cache[dependency.hash] ||= begin
         | 
| 181 | 
            -
                    @ | 
| 201 | 
            +
                    collection = @by_gem[dependency.name].gems if @by_gem[dependency.name]
         | 
| 202 | 
            +
                    collection ||= @specs
         | 
| 203 | 
            +
                    collection[dependency.name].select do |spec|
         | 
| 182 204 | 
             
                      match = dependency =~ spec
         | 
| 183 205 | 
             
                      match &= dependency.version_requirements.prerelease? if spec.version.prerelease?
         | 
| 184 206 | 
             
                      match
         | 
    
        data/lib/bundler/source.rb
    CHANGED
    
    | @@ -1,8 +1,23 @@ | |
| 1 1 | 
             
            module Bundler
         | 
| 2 | 
            +
              class DirectorySourceError < StandardError; end
         | 
| 3 | 
            +
              class GitSourceError < StandardError ; end
         | 
| 2 4 | 
             
              # Represents a source of rubygems. Initially, this is only gem repositories, but
         | 
| 3 5 | 
             
              # eventually, this will be git, svn, HTTP
         | 
| 4 6 | 
             
              class Source
         | 
| 5 7 | 
             
                attr_accessor :repository, :local
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                def initialize(options) ; end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
              private
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def process_source_gems(gems)
         | 
| 14 | 
            +
                  new_gems = Hash.new { |h,k| h[k] = [] }
         | 
| 15 | 
            +
                  gems.values.each do |spec|
         | 
| 16 | 
            +
                    spec.source = self
         | 
| 17 | 
            +
                    new_gems[spec.name] << spec
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                  new_gems
         | 
| 20 | 
            +
                end
         | 
| 6 21 | 
             
              end
         | 
| 7 22 |  | 
| 8 23 | 
             
              class GemSource < Source
         | 
| @@ -38,7 +53,7 @@ module Bundler | |
| 38 53 | 
             
                  destination = repository.path
         | 
| 39 54 |  | 
| 40 55 | 
             
                  unless destination.writable?
         | 
| 41 | 
            -
                    raise RubygemsRetardation
         | 
| 56 | 
            +
                    raise RubygemsRetardation, "destination: #{destination} is not writable"
         | 
| 42 57 | 
             
                  end
         | 
| 43 58 |  | 
| 44 59 | 
             
                  # Download the gem
         | 
| @@ -65,10 +80,11 @@ module Bundler | |
| 65 80 | 
             
                    index = Marshal.load(main_index)
         | 
| 66 81 | 
             
                  end
         | 
| 67 82 |  | 
| 68 | 
            -
                  gems = {}
         | 
| 83 | 
            +
                  gems = Hash.new { |h,k| h[k] = [] }
         | 
| 69 84 | 
             
                  index.each do |name, version, platform|
         | 
| 70 85 | 
             
                    spec = RemoteSpecification.new(name, version, platform, @uri)
         | 
| 71 | 
            -
                     | 
| 86 | 
            +
                    spec.source = self
         | 
| 87 | 
            +
                    gems[spec.name] << spec if Gem::Platform.match(spec.platform)
         | 
| 72 88 | 
             
                  end
         | 
| 73 89 | 
             
                  gems
         | 
| 74 90 | 
             
                rescue Gem::RemoteFetcher::FetchError => e
         | 
| @@ -77,8 +93,13 @@ module Bundler | |
| 77 93 | 
             
              end
         | 
| 78 94 |  | 
| 79 95 | 
             
              class SystemGemSource < Source
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                def self.instance
         | 
| 98 | 
            +
                  @instance ||= new({})
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 80 101 | 
             
                def initialize(options)
         | 
| 81 | 
            -
                   | 
| 102 | 
            +
                  @source = Gem::SourceIndex.from_installed_gems
         | 
| 82 103 | 
             
                end
         | 
| 83 104 |  | 
| 84 105 | 
             
                def can_be_local?
         | 
| @@ -86,7 +107,7 @@ module Bundler | |
| 86 107 | 
             
                end
         | 
| 87 108 |  | 
| 88 109 | 
             
                def gems
         | 
| 89 | 
            -
                  @ | 
| 110 | 
            +
                  @gems ||= process_source_gems(@source.gems)
         | 
| 90 111 | 
             
                end
         | 
| 91 112 |  | 
| 92 113 | 
             
                def ==(other)
         | 
| @@ -98,9 +119,6 @@ module Bundler | |
| 98 119 | 
             
                end
         | 
| 99 120 |  | 
| 100 121 | 
             
                def download(spec)
         | 
| 101 | 
            -
                  # gemfile = Pathname.new(local.loaded_from)
         | 
| 102 | 
            -
                  # gemfile = gemfile.dirname.join('..', 'cache', "#{local.full_name}.gem").expand_path
         | 
| 103 | 
            -
                  # repository.cache(File.join(Gem.dir, "cache", "#{local.full_name}.gem"))
         | 
| 104 122 | 
             
                  gemfile = Pathname.new(spec.loaded_from)
         | 
| 105 123 | 
             
                  gemfile = gemfile.dirname.join('..', 'cache', "#{spec.full_name}.gem")
         | 
| 106 124 | 
             
                  repository.cache(gemfile)
         | 
| @@ -108,10 +126,6 @@ module Bundler | |
| 108 126 |  | 
| 109 127 | 
             
              private
         | 
| 110 128 |  | 
| 111 | 
            -
                def fetch_specs
         | 
| 112 | 
            -
             | 
| 113 | 
            -
                end
         | 
| 114 | 
            -
             | 
| 115 129 | 
             
              end
         | 
| 116 130 |  | 
| 117 131 | 
             
              class GemDirectorySource < Source
         | 
| @@ -144,11 +158,12 @@ module Bundler | |
| 144 158 | 
             
              private
         | 
| 145 159 |  | 
| 146 160 | 
             
                def fetch_specs
         | 
| 147 | 
            -
                  specs = {}
         | 
| 161 | 
            +
                  specs = Hash.new { |h,k| h[k] = [] }
         | 
| 148 162 |  | 
| 149 163 | 
             
                  Dir["#{@location}/*.gem"].each do |gemfile|
         | 
| 150 164 | 
             
                    spec = Gem::Format.from_file_by_path(gemfile).spec
         | 
| 151 | 
            -
                     | 
| 165 | 
            +
                    spec.source = self
         | 
| 166 | 
            +
                    specs[spec.name] << spec
         | 
| 152 167 | 
             
                  end
         | 
| 153 168 |  | 
| 154 169 | 
             
                  specs
         | 
| @@ -156,13 +171,23 @@ module Bundler | |
| 156 171 | 
             
              end
         | 
| 157 172 |  | 
| 158 173 | 
             
              class DirectorySource < Source
         | 
| 159 | 
            -
                attr_reader :location
         | 
| 174 | 
            +
                attr_reader :location, :specs, :required_specs
         | 
| 160 175 |  | 
| 161 176 | 
             
                def initialize(options)
         | 
| 162 | 
            -
                   | 
| 163 | 
            -
             | 
| 164 | 
            -
                   | 
| 165 | 
            -
                  @ | 
| 177 | 
            +
                  if options[:location]
         | 
| 178 | 
            +
                    @location = Pathname.new(options[:location]).expand_path
         | 
| 179 | 
            +
                  end
         | 
| 180 | 
            +
                  @glob           = options[:glob] || "**/*.gemspec"
         | 
| 181 | 
            +
                  @specs          = {}
         | 
| 182 | 
            +
                  @required_specs = []
         | 
| 183 | 
            +
                end
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                def add_spec(path, name, version, require_paths = %w(lib))
         | 
| 186 | 
            +
                  raise DirectorySourceError, "already have a gem defined for '#{path}'" if @specs[path.to_s]
         | 
| 187 | 
            +
                  @specs[path.to_s] = Gem::Specification.new do |s|
         | 
| 188 | 
            +
                    s.name     = name
         | 
| 189 | 
            +
                    s.version  = Gem::Version.new(version)
         | 
| 190 | 
            +
                  end
         | 
| 166 191 | 
             
                end
         | 
| 167 192 |  | 
| 168 193 | 
             
                def can_be_local?
         | 
| @@ -171,67 +196,70 @@ module Bundler | |
| 171 196 |  | 
| 172 197 | 
             
                def gems
         | 
| 173 198 | 
             
                  @gems ||= begin
         | 
| 174 | 
            -
                     | 
| 175 | 
            -
             | 
| 176 | 
            -
                     | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
                       | 
| 180 | 
            -
                         | 
| 181 | 
            -
             | 
| 199 | 
            +
                    # Locate all gemspecs from the directory
         | 
| 200 | 
            +
                    specs = locate_gemspecs
         | 
| 201 | 
            +
                    specs = merge_defined_specs(specs)
         | 
| 202 | 
            +
             | 
| 203 | 
            +
                    required_specs.each do |required|
         | 
| 204 | 
            +
                      unless specs.any? {|k,v| v.name == required }
         | 
| 205 | 
            +
                        raise DirectorySourceError, "No gemspec for '#{required}' was found in" \
         | 
| 206 | 
            +
                          " '#{location}'. Please explicitly specify a version."
         | 
| 182 207 | 
             
                      end
         | 
| 183 208 | 
             
                    end
         | 
| 184 209 |  | 
| 185 | 
            -
                     | 
| 186 | 
            -
             | 
| 187 | 
            -
             | 
| 188 | 
            -
                      when @version.nil?
         | 
| 189 | 
            -
                        raise ArgumentError, "If you use :at, you must specify the gem " \
         | 
| 190 | 
            -
                          "and version you wish to stand in for"
         | 
| 191 | 
            -
                      when !Gem::Version.correct?(@version)
         | 
| 192 | 
            -
                        raise ArgumentError, "If you use :at, you must specify a gem and " \
         | 
| 193 | 
            -
                          "version. You specified #{@version} for the version"
         | 
| 194 | 
            -
                      end
         | 
| 210 | 
            +
                    process_source_gems(specs)
         | 
| 211 | 
            +
                  end
         | 
| 212 | 
            +
                end
         | 
| 195 213 |  | 
| 196 | 
            -
             | 
| 197 | 
            -
             | 
| 198 | 
            -
             | 
| 199 | 
            -
             | 
| 200 | 
            -
                       | 
| 201 | 
            -
                      specs[ | 
| 214 | 
            +
                def locate_gemspecs
         | 
| 215 | 
            +
                  Dir["#{location}/#{@glob}"].inject({}) do |specs, file|
         | 
| 216 | 
            +
                    file = Pathname.new(file)
         | 
| 217 | 
            +
                    if spec = eval(File.read(file)) and validate_gemspec(file.dirname, spec)
         | 
| 218 | 
            +
                      spec.location = file.dirname.expand_path
         | 
| 219 | 
            +
                      specs[spec.full_name] = spec
         | 
| 202 220 | 
             
                    end
         | 
| 203 | 
            -
             | 
| 204 221 | 
             
                    specs
         | 
| 205 222 | 
             
                  end
         | 
| 206 223 | 
             
                end
         | 
| 207 224 |  | 
| 208 | 
            -
                 | 
| 209 | 
            -
             | 
| 210 | 
            -
             | 
| 211 | 
            -
             | 
| 212 | 
            -
             | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 225 | 
            +
                def merge_defined_specs(specs)
         | 
| 226 | 
            +
                  @specs.each do |path, spec|
         | 
| 227 | 
            +
                    # Set the spec location
         | 
| 228 | 
            +
                    spec.location = "#{location}/#{path}"
         | 
| 229 | 
            +
             | 
| 230 | 
            +
                    if existing = specs.values.find { |s| s.name == spec.name }
         | 
| 231 | 
            +
                      if existing.version != spec.version
         | 
| 232 | 
            +
                        raise DirectorySourceError, "The version you specified for #{spec.name}" \
         | 
| 233 | 
            +
                          " is #{spec.version}. The gemspec is #{existing.version}."
         | 
| 234 | 
            +
                      # Not sure if this is needed
         | 
| 235 | 
            +
                      # ====
         | 
| 236 | 
            +
                      # elsif File.expand_path(existing.location) != File.expand_path(spec.location)
         | 
| 237 | 
            +
                      #   raise DirectorySourceError, "The location you specified for #{spec.name}" \
         | 
| 238 | 
            +
                      #     " is '#{spec.location}'. The gemspec was found at '#{existing.location}'."
         | 
| 239 | 
            +
                      end
         | 
| 240 | 
            +
                    elsif !validate_gemspec(spec.location, spec)
         | 
| 241 | 
            +
                      raise "Your gem definition is not valid: #{spec}"
         | 
| 242 | 
            +
                    else
         | 
| 243 | 
            +
                      specs[spec.full_name] = spec
         | 
| 244 | 
            +
                    end
         | 
| 245 | 
            +
                  end
         | 
| 246 | 
            +
                  specs
         | 
| 247 | 
            +
                end
         | 
| 248 | 
            +
             | 
| 249 | 
            +
                def validate_gemspec(path, spec)
         | 
| 250 | 
            +
                  path = Pathname.new(path)
         | 
| 223 251 | 
             
                  msg  = "Gemspec for #{spec.name} (#{spec.version}) is invalid:"
         | 
| 224 252 | 
             
                  # Check the require_paths
         | 
| 225 | 
            -
                  (spec.require_paths || []).each do | | 
| 226 | 
            -
                    unless  | 
| 227 | 
            -
                      Bundler.logger.warn "#{msg} Missing require path: '#{ | 
| 253 | 
            +
                  (spec.require_paths || []).each do |require_path|
         | 
| 254 | 
            +
                    unless path.join(require_path).directory?
         | 
| 255 | 
            +
                      Bundler.logger.warn "#{msg} Missing require path: '#{require_path}'"
         | 
| 228 256 | 
             
                      return false
         | 
| 229 257 | 
             
                    end
         | 
| 230 258 | 
             
                  end
         | 
| 231 259 |  | 
| 232 260 | 
             
                  # Check the executables
         | 
| 233 261 | 
             
                  (spec.executables || []).each do |exec|
         | 
| 234 | 
            -
                    unless  | 
| 262 | 
            +
                    unless path.join(spec.bindir, exec).file?
         | 
| 235 263 | 
             
                      Bundler.logger.warn "#{msg} Missing executable: '#{File.join(spec.bindir, exec)}'"
         | 
| 236 264 | 
             
                      return false
         | 
| 237 265 | 
             
                    end
         | 
| @@ -255,6 +283,8 @@ module Bundler | |
| 255 283 | 
             
              end
         | 
| 256 284 |  | 
| 257 285 | 
             
              class GitSource < DirectorySource
         | 
| 286 | 
            +
                attr_reader :ref, :uri, :branch
         | 
| 287 | 
            +
             | 
| 258 288 | 
             
                def initialize(options)
         | 
| 259 289 | 
             
                  super
         | 
| 260 290 | 
             
                  @uri = options[:uri]
         | 
| @@ -281,9 +311,9 @@ module Bundler | |
| 281 311 | 
             
                    `git clone #{@uri} #{location} --no-hardlinks`
         | 
| 282 312 |  | 
| 283 313 | 
             
                    if @ref
         | 
| 284 | 
            -
                      Dir.chdir(location) { `git checkout #{@ref}` }
         | 
| 314 | 
            +
                      Dir.chdir(location) { `git checkout --quiet #{@ref}` }
         | 
| 285 315 | 
             
                    elsif @branch && @branch != "master"
         | 
| 286 | 
            -
                      Dir.chdir(location) { `git checkout origin/#{@branch}` }
         | 
| 316 | 
            +
                      Dir.chdir(location) { `git checkout --quiet origin/#{@branch}` }
         | 
| 287 317 | 
             
                    end
         | 
| 288 318 | 
             
                  end
         | 
| 289 319 | 
             
                  super
         | 
| @@ -20,9 +20,14 @@ module Bundler | |
| 20 20 | 
             
              require "rubygems"
         | 
| 21 21 |  | 
| 22 22 | 
             
              @bundled_specs = {}
         | 
| 23 | 
            -
            <%  | 
| 24 | 
            -
             | 
| 25 | 
            -
               | 
| 23 | 
            +
            <% specs.each do |spec| -%>
         | 
| 24 | 
            +
            <% if options[:no_bundle].include?(spec.name) -%>
         | 
| 25 | 
            +
              gem "<%= spec.name %>", "<%= spec.version %>"
         | 
| 26 | 
            +
            <% else -%>
         | 
| 27 | 
            +
            <% path = spec_file_for(spec) -%>
         | 
| 28 | 
            +
              @bundled_specs["<%= spec.name %>"] = eval(File.read("#{dir}/<%= path %>"))
         | 
| 29 | 
            +
              @bundled_specs["<%= spec.name %>"].loaded_from = "#{dir}/<%= path %>"
         | 
| 30 | 
            +
            <% end -%>
         | 
| 26 31 | 
             
            <% end -%>
         | 
| 27 32 |  | 
| 28 33 | 
             
              def self.add_specs_to_loaded_specs
         | 
| @@ -42,51 +47,62 @@ module Bundler | |
| 42 47 | 
             
              def self.require_env(env = nil)
         | 
| 43 48 | 
             
                context = Class.new do
         | 
| 44 49 | 
             
                  def initialize(env) @env = env && env.to_s ; end
         | 
| 45 | 
            -
                  def method_missing(*) ; end
         | 
| 46 | 
            -
                  def only(env)
         | 
| 47 | 
            -
                    old, @only = @only,  | 
| 50 | 
            +
                  def method_missing(*) ; yield if block_given? ; end
         | 
| 51 | 
            +
                  def only(*env)
         | 
| 52 | 
            +
                    old, @only = @only, _combine_only(env.flatten)
         | 
| 48 53 | 
             
                    yield
         | 
| 49 54 | 
             
                    @only = old
         | 
| 50 55 | 
             
                  end
         | 
| 51 | 
            -
                  def except(env)
         | 
| 52 | 
            -
                    old, @except = @except,  | 
| 56 | 
            +
                  def except(*env)
         | 
| 57 | 
            +
                    old, @except = @except, _combine_except(env.flatten)
         | 
| 53 58 | 
             
                    yield
         | 
| 54 59 | 
             
                    @except = old
         | 
| 55 60 | 
             
                  end
         | 
| 56 61 | 
             
                  def gem(name, *args)
         | 
| 57 | 
            -
                    opt = args.last  | 
| 58 | 
            -
                    only =  | 
| 59 | 
            -
                    except =  | 
| 62 | 
            +
                    opt = args.last.is_a?(Hash) ? args.pop : {}
         | 
| 63 | 
            +
                    only = _combine_only(opt[:only] || opt["only"])
         | 
| 64 | 
            +
                    except = _combine_except(opt[:except] || opt["except"])
         | 
| 60 65 | 
             
                    files = opt[:require_as] || opt["require_as"] || name
         | 
| 61 66 | 
             
                    files = [files] unless files.respond_to?(:each)
         | 
| 62 67 |  | 
| 63 68 | 
             
                    return unless !only || only.any? {|e| e == @env }
         | 
| 64 69 | 
             
                    return if except && except.any? {|e| e == @env }
         | 
| 65 70 |  | 
| 66 | 
            -
                    files | 
| 71 | 
            +
                    if files = opt[:require_as] || opt["require_as"]
         | 
| 72 | 
            +
                      files = Array(files)
         | 
| 73 | 
            +
                      files.each { |f| require f }
         | 
| 74 | 
            +
                    else
         | 
| 75 | 
            +
                      begin
         | 
| 76 | 
            +
                        require name
         | 
| 77 | 
            +
                      rescue LoadError
         | 
| 78 | 
            +
                        # Do nothing
         | 
| 79 | 
            +
                      end
         | 
| 80 | 
            +
                    end
         | 
| 67 81 | 
             
                    yield if block_given?
         | 
| 68 82 | 
             
                    true
         | 
| 69 83 | 
             
                  end
         | 
| 70 84 | 
             
                  private
         | 
| 71 | 
            -
                  def  | 
| 85 | 
            +
                  def _combine_only(only)
         | 
| 72 86 | 
             
                    return @only unless only
         | 
| 73 87 | 
             
                    only = [only].flatten.compact.uniq.map { |o| o.to_s }
         | 
| 74 88 | 
             
                    only &= @only if @only
         | 
| 75 89 | 
             
                    only
         | 
| 76 90 | 
             
                  end
         | 
| 77 | 
            -
                  def  | 
| 91 | 
            +
                  def _combine_except(except)
         | 
| 78 92 | 
             
                    return @except unless except
         | 
| 79 93 | 
             
                    except = [except].flatten.compact.uniq.map { |o| o.to_s }
         | 
| 80 94 | 
             
                    except |= @except if @except
         | 
| 81 95 | 
             
                    except
         | 
| 82 96 | 
             
                  end
         | 
| 83 97 | 
             
                end
         | 
| 84 | 
            -
                context.new(env && env.to_s).instance_eval(File.read(@gemfile))
         | 
| 98 | 
            +
                context.new(env && env.to_s).instance_eval(File.read(@gemfile), @gemfile, 1)
         | 
| 85 99 | 
             
              end
         | 
| 86 100 | 
             
            end
         | 
| 87 101 |  | 
| 88 102 | 
             
            <% if options[:rubygems] -%>
         | 
| 89 103 | 
             
            module Gem
         | 
| 104 | 
            +
              @loaded_stacks = Hash.new { |h,k| h[k] = [] }
         | 
| 105 | 
            +
             | 
| 90 106 | 
             
              def source_index.refresh!
         | 
| 91 107 | 
             
                super
         | 
| 92 108 | 
             
                Bundler.add_specs_to_index
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: bundler
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.7.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors: 
         | 
| 7 7 | 
             
            - Yehuda Katz
         | 
| @@ -10,7 +10,7 @@ autorequire: | |
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 12 |  | 
| 13 | 
            -
            date: 2009- | 
| 13 | 
            +
            date: 2009-11-05 00:00:00 -08:00
         | 
| 14 14 | 
             
            default_executable: 
         | 
| 15 15 | 
             
            dependencies: []
         | 
| 16 16 |  |