Skip to content

Commit

Permalink
Starting to refactor the Bundler to get it ready for multiple kinds o…
Browse files Browse the repository at this point in the history
…f sources
  • Loading branch information
Carl Lerche committed Jul 30, 2009
1 parent d14390b commit 0785b65
Show file tree
Hide file tree
Showing 14 changed files with 138 additions and 248 deletions.
1 change: 1 addition & 0 deletions lib/bundler.rb
Expand Up @@ -7,6 +7,7 @@
require "rubygems/installer"

require "bundler/gem_bundle"
require "bundler/source"
require "bundler/finder"
require "bundler/gem_ext"
require "bundler/resolver"
Expand Down
59 changes: 19 additions & 40 deletions lib/bundler/finder.rb
Expand Up @@ -13,10 +13,9 @@ class Finder
# ==== 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) }
@cache = {}
@index = {}
@sources = sources
end

# Figures out the best possible configuration of gems that satisfies
Expand All @@ -36,39 +35,6 @@ def resolve(*dependencies)
resolved && GemBundle.new(resolved)
end

# Fetches the index from the remote source
#
# ==== Parameters
# source<String>:: URI pointing to the gem repository
#
# ==== Raises
# ArgumentError:: If the source is not a valid gem repository
def fetch(source)
Bundler.logger.info "Updating source: #{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

# Adds a new gem index linked to a gem source to the over all
# gem index that gets searched.
#
# ==== Parameters
# index<Gem::SourceIndex>:: The index to append to the list
# source<String>:: The original source
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
end

# Searches for a gem that matches the dependency
#
# ==== Parameters
Expand All @@ -78,12 +44,25 @@ def append(index, source)
# [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
9 changes: 2 additions & 7 deletions lib/bundler/gem_bundle.rb
@@ -1,13 +1,8 @@
module Bundler
class GemBundle < Array
def download(directory)
FileUtils.mkdir_p(directory)

def download(repository)
sort_by {|s| s.full_name.downcase }.each do |spec|
unless directory.join("cache", "#{spec.full_name}.gem").file?
Bundler.logger.info "Downloading #{spec.full_name}.gem"
Gem::RemoteFetcher.fetcher.download(spec, spec.source, directory)
end
repository.download(spec)
end

self
Expand Down
4 changes: 2 additions & 2 deletions lib/bundler/gem_ext.rb
Expand Up @@ -12,8 +12,8 @@ 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?
source = Bundler::Source.new(source) unless source.is_a?(Bundler::Source)
@source = source
end
end
end
3 changes: 1 addition & 2 deletions lib/bundler/manifest.rb
Expand Up @@ -7,7 +7,6 @@ class Manifest
attr_reader :sources, :dependencies, :path

def initialize(sources, dependencies, bindir, repository_path, rubygems, system_gems)
sources.map! {|s| s.is_a?(URI) ? s : URI.parse(s) }
@sources = sources
@dependencies = dependencies
@bindir = bindir
Expand Down Expand Up @@ -58,7 +57,7 @@ def fetch(update)
raise VersionConflict, "No compatible versions could be found for:\n#{gems}"
end

bundle.download(@repository.path)
bundle.download(@repository)
end

def gem_dependencies
Expand Down
2 changes: 1 addition & 1 deletion lib/bundler/manifest_file.rb
Expand Up @@ -11,7 +11,7 @@ def self.load(filename = nil)

def initialize(filename)
@filename = filename
@sources = %w(http://gems.rubyforge.org)
@sources = [Source.new("http://gems.rubyforge.org")]
@dependencies = []
@rubygems = true
@system_gems = true
Expand Down
8 changes: 8 additions & 0 deletions lib/bundler/repository.rb
Expand Up @@ -22,6 +22,14 @@ def valid?
(Dir[@path.join("*")] - Dir[@path.join("{cache,doc,gems,environments,specifications}")]).empty?
end

def download(spec)
FileUtils.mkdir_p(@path)

unless @path.join("cache", "#{spec.full_name}.gem").file?
spec.source.download(spec, @path)
end
end

# Checks whether a gem is installed
def install_cached_gems(options = {})
cached_gems.each do |name, version|
Expand Down
6 changes: 4 additions & 2 deletions lib/bundler/runtime.rb
Expand Up @@ -41,8 +41,10 @@ def disable_system_gems
end

def source(source)
@manifest_file.sources << source
@manifest_file.sources.uniq!
source = Source.new(source)
unless @manifest_file.sources.include?(source)
@manifest_file.sources << source
end
end

def sources
Expand Down
51 changes: 51 additions & 0 deletions lib/bundler/source.rb
@@ -0,0 +1,51 @@
module Bundler
# Represents a source of rubygems. Initially, this is only gem repositories, but
# eventually, this will be git, svn, HTTP
class Source
attr_reader :uri

def initialize(uri)
@uri = uri.is_a?(URI) ? uri : URI.parse(uri)
raise ArgumentError, "The source must be an absolute URI" unless @uri.absolute?
end

def specs
@specs ||= fetch_specs
end

def ==(other)
uri == other.uri
end

def to_s
@uri.to_s
end

def download(spec, destination)
Bundler.logger.info "Downloading #{spec.full_name}.gem"
Gem::RemoteFetcher.fetcher.download(spec, uri, destination)
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)
specs = Hash.new { |h,k| h[k] = {} }

index.gems.values.each do |spec|
next unless Gem::Platform.match(spec.platform)
spec.source = self
specs[spec.name][spec.version] = spec
end

specs
rescue Gem::RemoteFetcher::FetchError => e
raise ArgumentError, "#{to_s} is not a valid source: #{e.message}"
end
end
end
125 changes: 0 additions & 125 deletions spec/bundler/dsl_spec.rb

This file was deleted.

0 comments on commit 0785b65

Please sign in to comment.