lib/bundler/source.rb in bundler-0.9.7 vs lib/bundler/source.rb in bundler-0.9.8

- old
+ new

@@ -1,6 +1,7 @@ -require "rubygems/remote_fetcher" +require "uri" +require "rubygems/spec_fetcher" require "rubygems/format" require "digest/sha1" require "open3" module Bundler @@ -8,11 +9,12 @@ class Rubygems attr_reader :uri, :options def initialize(options = {}) @options = options - @uri = options["uri"] + @uri = options["uri"].to_s + @uri = "#{uri}/" unless @uri =~ %r'/$' @uri = URI.parse(@uri) unless @uri.is_a?(URI) raise ArgumentError, "The source must be an absolute URI" unless @uri.absolute? end def to_s @@ -21,17 +23,18 @@ def specs @specs ||= fetch_specs end - def install(spec) - destination = Gem.dir - + def fetch(spec) Bundler.ui.debug " * Downloading" - gem_path = Gem::RemoteFetcher.fetcher.download(spec, uri, destination) + Gem::RemoteFetcher.fetcher.download(spec, uri, Gem.dir) + end + + def install(spec) Bundler.ui.debug " * Installing" - installer = Gem::Installer.new gem_path, + installer = Gem::Installer.new gem_path(spec), :install_dir => Gem.dir, :ignore_dependencies => true, :wrappers => true, :env_shebang => true, :bin_dir => "#{Gem.dir}/bin" @@ -39,42 +42,45 @@ installer.install end private + def gem_path(spec) + "#{Gem.dir}/cache/#{spec.full_name}.gem" + end + def fetch_specs index = Index.new Bundler.ui.info "Fetching source index from #{uri}" - (main_specs + prerelease_specs).each do |name, version, platform| - next unless Gem::Platform.match(platform) - spec = RemoteSpecification.new(name, version, platform, @uri) - spec.source = self - index << spec + old, Gem.sources = Gem.sources, ["#{uri}"] + + fetch_all_specs do |n,v| + v.each do |name, version, platform| + next unless Gem::Platform.match(platform) + spec = RemoteSpecification.new(name, version, platform, @uri) + spec.source = self + index << spec + end end + index.freeze + ensure + Gem.sources = old end - def main_specs - Marshal.load(Gem::RemoteFetcher.fetcher.fetch_path("#{uri}/specs.4.8.gz")) - rescue Gem::RemoteFetcher::FetchError => e - raise ArgumentError, "#{to_s} is not a valid source: #{e.message}" + def fetch_all_specs(&blk) + Gem::SpecFetcher.new.list(true, false).each(&blk) + Gem::SpecFetcher.new.list(false, true).each(&blk) end - - def prerelease_specs - Marshal.load(Gem::RemoteFetcher.fetcher.fetch_path("#{uri}/prerelease_specs.4.8.gz")) - rescue Gem::RemoteFetcher::FetchError - Bundler.ui.warn "Source '#{uri}' does not support prerelease gems" - [] - end end class SystemGems def specs @specs ||= begin index = Index.new - Gem::SourceIndex.from_installed_gems.each do |name, spec| + Gem::SourceIndex.from_installed_gems.reverse_each do |name, spec| spec.source = self index << spec end index @@ -99,26 +105,20 @@ ".gem files at #{@path}" end def specs @specs ||= begin - index = Index.new - - Dir["#{@path}/*.gem"].each do |gemfile| - spec = Gem::Format.from_file_by_path(gemfile).spec - spec.source = self - index << spec - end - - index.freeze + specs = Index.from_cached_specs(@path) + specs.each { |s| s.source = self } + specs end end def install(spec) destination = Gem.dir - Bundler.ui.debug " * Installing from pack" + Bundler.ui.debug " * Installing from cache" installer = Gem::Installer.new "#{@path}/#{spec.full_name}.gem", :install_dir => Gem.dir, :ignore_dependencies => true, :wrappers => true, :env_shebang => true, @@ -127,92 +127,108 @@ installer.install end end class Path - attr_reader :path, :options + attr_reader :path, :options, :default_spec def initialize(options) @options = options @glob = options["glob"] || "{,*/}*.gemspec" - @path = options["path"] - @default_spec = nil + + if options["path"] + @path = Pathname.new(options["path"]).expand_path(Bundler.root) + end + + if options["name"] + @default_spec = Specification.new do |s| + s.name = options["name"] + s.source = self + s.version = Gem::Version.new(options["version"]) + s.summary = "Fake gemspec for #{options["name"]}" + s.relative_loaded_from = "#{options["name"]}.gemspec" + end + end end def to_s "source code at #{@path}" end - def default_spec(*args) - return @default_spec if args.empty? - name, version = *args - @default_spec = Specification.new do |s| - s.name = name - s.source = self - s.version = Gem::Version.new(version) - s.relative_loaded_from = "#{name}.gemspec" - end - end + def load_spec_files + index = Index.new - def local_specs - @local_specs ||= begin - index = Index.new - - if File.directory?(path) - Dir["#{path}/#{@glob}"].each do |file| - file = Pathname.new(file) - relative_path = file.relative_path_from(Pathname.new(path)) - # Do it in the root of the repo in case they do - # assume being in the root - if spec = Dir.chdir(path) { eval(File.read(relative_path)) } - spec = Specification.from_gemspec(spec) - spec.loaded_from = file - spec.source = self - index << spec - end + if File.directory?(path) + Dir["#{path}/#{@glob}"].each do |file| + file = Pathname.new(file) + # Eval the gemspec from its parent directory + if spec = Dir.chdir(file.dirname) { eval(File.read(file.basename)) } + spec = Specification.from_gemspec(spec) + spec.loaded_from = file.to_s + spec.source = self + index << spec end - - index << default_spec if default_spec && index.empty? end - index.freeze + index << default_spec if default_spec && index.empty? end + + index.freeze end + def local_specs + @local_specs ||= load_spec_files + end + def install(spec) Bundler.ui.debug " * Using path #{path}" generate_bin(spec) end alias specs local_specs private def generate_bin(spec) - # HAX -- Generate the bin - bin_dir = "#{Gem.dir}/bin" - gem_dir = spec.full_gem_path - installer = Gem::Installer.allocate - installer.instance_eval do - @spec = spec - @bin_dir = bin_dir - @gem_dir = gem_dir - @wrappers = true - @env_shebang = false - @format_executable = false + gem_dir = spec.full_gem_path + gem_file = nil # so we have access once after it's set in the block + + Dir.chdir(gem_dir) do + gem_file = Gem::Builder.new(spec).build end + + installer = Gem::Installer.new File.join(gem_dir, gem_file), + :bin_dir => "#{Gem.dir}/bin", + :wrappers => true, + :env_shebang => false, + :format_executable => false + + installer.instance_eval { @gem_dir = gem_dir } + + installer.build_extensions installer.generate_bin + rescue Gem::InvalidSpecificationException => e + Bundler.ui.warn "\n#{spec.name} at #{spec.full_gem_path} did not have a valid gemspec.\n" \ + "This prevents bundler from installing bins or native extensions, but " \ + "that may not affect its functionality." + + if !spec.extensions.empty? && !spec.emails.empty? + Bundler.ui.warn "If you need to use this package without installing it from a gem " \ + "repository, please contact #{spec.emails.join(", or ")} and ask them " \ + "to modify their .gemspec so it can work with `gem build`." + end + + Bundler.ui.warn "The validation message from Rubygems was:\n #{e.message}" end end class Git < Path attr_reader :uri, :ref, :options def initialize(options) - @options = options - @glob = options["glob"] || "{,*/}*.gemspec" + super @uri = options["uri"] @ref = options["ref"] || options["branch"] || 'master' end def to_s @@ -223,36 +239,13 @@ def path Bundler.install_path.join("#{base_name}-#{uri_hash}-#{ref}") end def specs - @specs ||= begin - index = Index.new - # Start by making sure the git cache is up to date - cache - # Find all gemspecs in the repo - in_cache do - out = %x(git ls-tree -r #{revision}).strip - lines = out.split("\n").select { |l| l =~ /\.gemspec$/ } - # Loop over the lines and extract the relative path and the - # git hash - lines.each do |line| - next unless line =~ %r{^(\d+) (blob|tree) ([a-f0-9]+)\t(.*)$} - hash, file = $3, $4 - # Read the gemspec - if spec = eval(%x(git cat-file blob #{$3})) - spec = Specification.from_gemspec(spec) - spec.relative_loaded_from = file - spec.source = self - index << spec - end - end - end - - index << default_spec if default_spec && index.empty? - - index.freeze - end + # Start by making sure the git cache is up to date + cache + checkout + @specs ||= load_spec_files end def install(spec) Bundler.ui.debug " * Using git #{uri}"